AGS: Initial addition of engine/ and shared/ folders

This commit is contained in:
Paul Gilbert 2020-11-21 08:30:51 -08:00
parent df58db6659
commit a60d290a08
642 changed files with 123412 additions and 0 deletions

View file

@ -0,0 +1,67 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// Functions related to finding and opening game assets.
//
//=============================================================================
#ifndef __AGS_EE_AC__ASSETHELPER_H
#define __AGS_EE_AC__ASSETHELPER_H
#include <memory>
#include <utility>
#include "util/string.h"
namespace AGS { namespace Common {class Stream;}}
using AGS::Common::Stream;
using AGS::Common::String;
// Looks for valid asset library everywhere and returns path, or empty string if failed
String find_assetlib(const String &filename);
// Looks up for known valid asset library and returns path, or empty string if failed
String get_known_assetlib(const String &filename);
// Looks for asset everywhere and returns opened stream, or NULL if failed
Stream *find_open_asset(const String &filename);
extern "C" {
struct PACKFILE; // Allegro 4's own stream type
struct DUMBFILE; // DUMB stream type
}
// AssetPath combines asset library and item names
// TODO: implement support for registering multiple libraries at once for
// the AssetManager, then we could remove assetlib parameter.
typedef std::pair<String, String> AssetPath;
// 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, size_t &asset_size);
// Creates DUMBFILE stream from AGS asset. Used for creating DUMB objects
DUMBFILE *DUMBfileFromAsset(const AssetPath &path, size_t &asset_size);
bool DoesAssetExistInLib(const AssetPath &assetname);
#endif // __AGS_EE_AC__ASSETHELPER_H

View file

@ -0,0 +1,353 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/audiochannel.h"
#include "ac/gamestate.h"
#include "ac/global_audio.h"
#include "ac/dynobj/cc_audioclip.h"
#include "debug/debug_log.h"
#include "game/roomstruct.h"
#include "script/runtimescriptvalue.h"
#include "media/audio/audio_system.h"
using namespace AGS::Common;
extern GameState play;
extern RoomStruct thisroom;
extern CCAudioClip ccDynamicAudioClip;
int AudioChannel_GetID(ScriptAudioChannel *channel)
{
return channel->id;
}
int AudioChannel_GetIsPlaying(ScriptAudioChannel *channel)
{
if (play.fast_forward)
{
return 0;
}
return channel_is_playing(channel->id) ? 1 : 0;
}
int AudioChannel_GetPanning(ScriptAudioChannel *channel)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
return ch->panningAsPercentage;
}
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);
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
ch->set_panning(((newPanning + 100) * 255) / 200);
ch->panningAsPercentage = newPanning;
}
}
ScriptAudioClip* AudioChannel_GetPlayingClip(ScriptAudioChannel *channel)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
return (ScriptAudioClip*)ch->sourceClip;
}
return nullptr;
}
int AudioChannel_GetPosition(ScriptAudioChannel *channel)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
if (play.fast_forward)
return 999999999;
return ch->get_pos();
}
return 0;
}
int AudioChannel_GetPositionMs(ScriptAudioChannel *channel)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
if (play.fast_forward)
return 999999999;
return ch->get_pos_ms();
}
return 0;
}
int AudioChannel_GetLengthMs(ScriptAudioChannel *channel)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
return ch->get_length_ms();
}
return 0;
}
int AudioChannel_GetVolume(ScriptAudioChannel *channel)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
return ch->get_volume();
}
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);
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
ch->set_volume_percent(newVolume);
}
return 0;
}
int AudioChannel_GetSpeed(ScriptAudioChannel *channel)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
return ch->get_speed();
}
return 0;
}
void AudioChannel_SetSpeed(ScriptAudioChannel *channel, int new_speed)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
ch->set_speed(new_speed);
}
}
void AudioChannel_Stop(ScriptAudioChannel *channel)
{
if (channel->id == SCHAN_SPEECH && play.IsNonBlockingVoiceSpeech())
stop_voice_nonblocking();
else
stop_or_fade_out_channel(channel->id, -1, nullptr);
}
void AudioChannel_Seek(ScriptAudioChannel *channel, int newPosition)
{
if (newPosition < 0)
quitprintf("!AudioChannel.Seek: invalid seek position %d", newPosition);
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
ch->seek(newPosition);
}
}
void AudioChannel_SetRoomLocation(ScriptAudioChannel *channel, int xPos, int yPos)
{
AudioChannelsLock lock;
auto* ch = lock.GetChannelIfPlaying(channel->id);
if (ch)
{
int maxDist = ((xPos > thisroom.Width / 2) ? xPos : (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
//
//=============================================================================
#include "debug/out.h"
#include "script/script_api.h"
#include "script/script_runtime.h"
// 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, 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);
}
// 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);
}
void RegisterAudioChannelAPI()
{
ccAddExternalObjectFunction("AudioChannel::Seek^1", Sc_AudioChannel_Seek);
ccAddExternalObjectFunction("AudioChannel::SetRoomLocation^2", Sc_AudioChannel_SetRoomLocation);
ccAddExternalObjectFunction("AudioChannel::Stop^0", Sc_AudioChannel_Stop);
ccAddExternalObjectFunction("AudioChannel::get_ID", Sc_AudioChannel_GetID);
ccAddExternalObjectFunction("AudioChannel::get_IsPlaying", Sc_AudioChannel_GetIsPlaying);
ccAddExternalObjectFunction("AudioChannel::get_LengthMs", Sc_AudioChannel_GetLengthMs);
ccAddExternalObjectFunction("AudioChannel::get_Panning", Sc_AudioChannel_GetPanning);
ccAddExternalObjectFunction("AudioChannel::set_Panning", Sc_AudioChannel_SetPanning);
ccAddExternalObjectFunction("AudioChannel::get_PlayingClip", Sc_AudioChannel_GetPlayingClip);
ccAddExternalObjectFunction("AudioChannel::get_Position", Sc_AudioChannel_GetPosition);
ccAddExternalObjectFunction("AudioChannel::get_PositionMs", Sc_AudioChannel_GetPositionMs);
ccAddExternalObjectFunction("AudioChannel::get_Volume", Sc_AudioChannel_GetVolume);
ccAddExternalObjectFunction("AudioChannel::set_Volume", Sc_AudioChannel_SetVolume);
ccAddExternalObjectFunction("AudioChannel::get_Speed", Sc_AudioChannel_GetSpeed);
ccAddExternalObjectFunction("AudioChannel::set_Speed", Sc_AudioChannel_SetSpeed);
// For compatibility with Ahmet Kamil's (aka Gord10) custom engine
ccAddExternalObjectFunction("AudioChannel::SetSpeed^1", Sc_AudioChannel_SetSpeed);
/* ----------------------- Registering unsafe exports for plugins -----------------------*/
ccAddExternalFunctionForPlugin("AudioChannel::Seek^1", (void*)AudioChannel_Seek);
ccAddExternalFunctionForPlugin("AudioChannel::SetRoomLocation^2", (void*)AudioChannel_SetRoomLocation);
ccAddExternalFunctionForPlugin("AudioChannel::Stop^0", (void*)AudioChannel_Stop);
ccAddExternalFunctionForPlugin("AudioChannel::get_ID", (void*)AudioChannel_GetID);
ccAddExternalFunctionForPlugin("AudioChannel::get_IsPlaying", (void*)AudioChannel_GetIsPlaying);
ccAddExternalFunctionForPlugin("AudioChannel::get_LengthMs", (void*)AudioChannel_GetLengthMs);
ccAddExternalFunctionForPlugin("AudioChannel::get_Panning", (void*)AudioChannel_GetPanning);
ccAddExternalFunctionForPlugin("AudioChannel::set_Panning", (void*)AudioChannel_SetPanning);
ccAddExternalFunctionForPlugin("AudioChannel::get_PlayingClip", (void*)AudioChannel_GetPlayingClip);
ccAddExternalFunctionForPlugin("AudioChannel::get_Position", (void*)AudioChannel_GetPosition);
ccAddExternalFunctionForPlugin("AudioChannel::get_PositionMs", (void*)AudioChannel_GetPositionMs);
ccAddExternalFunctionForPlugin("AudioChannel::get_Volume", (void*)AudioChannel_GetVolume);
ccAddExternalFunctionForPlugin("AudioChannel::set_Volume", (void*)AudioChannel_SetVolume);
}

View file

@ -0,0 +1,38 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__AUDIOCHANNEL_H
#define __AGS_EE_AC__AUDIOCHANNEL_H
#include "ac/dynobj/scriptaudioclip.h"
#include "ac/dynobj/scriptaudiochannel.h"
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_SetRoomLocation(ScriptAudioChannel *channel, int xPos, int yPos);
#endif // __AGS_EE_AC__AUDIOCHANNEL_H

View file

@ -0,0 +1,154 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/asset_helper.h"
#include "ac/audioclip.h"
#include "ac/audiochannel.h"
#include "ac/gamesetupstruct.h"
#include "script/runtimescriptvalue.h"
#include "ac/dynobj/cc_audiochannel.h"
#include "media/audio/audio_system.h"
extern GameSetupStruct game;
extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
extern CCAudioChannel ccDynamicAudio;
int AudioClip_GetID(ScriptAudioClip *clip)
{
return clip->id;
}
int AudioClip_GetFileType(ScriptAudioClip *clip)
{
return clip->fileType;
}
int AudioClip_GetType(ScriptAudioClip *clip)
{
return clip->type;
}
int AudioClip_GetIsAvailable(ScriptAudioClip *clip)
{
return DoesAssetExistInLib(get_audio_clip_assetpath(clip->bundlingType, clip->fileName)) ? 1 : 0;
}
void AudioClip_Stop(ScriptAudioClip *clip)
{
AudioChannelsLock lock;
for (int i = 0; i < MAX_SOUND_CHANNELS; i++)
{
auto* ch = lock.GetChannelIfPlaying(i);
if ((ch != nullptr) && (ch->sourceClip == clip))
{
AudioChannel_Stop(&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;
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
#include "debug/out.h"
#include "script/script_api.h"
#include "script/script_runtime.h"
RuntimeScriptValue Sc_AudioClip_GetID(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
API_OBJCALL_INT(ScriptAudioClip, AudioClip_GetID);
}
// 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, 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, 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, ccDynamicAudio, AudioClip_PlayQueued);
}
void RegisterAudioClipAPI()
{
ccAddExternalObjectFunction("AudioClip::Play^2", Sc_AudioClip_Play);
ccAddExternalObjectFunction("AudioClip::PlayFrom^3", Sc_AudioClip_PlayFrom);
ccAddExternalObjectFunction("AudioClip::PlayQueued^2", Sc_AudioClip_PlayQueued);
ccAddExternalObjectFunction("AudioClip::Stop^0", Sc_AudioClip_Stop);
ccAddExternalObjectFunction("AudioClip::get_ID", Sc_AudioClip_GetID);
ccAddExternalObjectFunction("AudioClip::get_FileType", Sc_AudioClip_GetFileType);
ccAddExternalObjectFunction("AudioClip::get_IsAvailable", Sc_AudioClip_GetIsAvailable);
ccAddExternalObjectFunction("AudioClip::get_Type", Sc_AudioClip_GetType);
/* ----------------------- Registering unsafe exports for plugins -----------------------*/
ccAddExternalFunctionForPlugin("AudioClip::Play^2", (void*)AudioClip_Play);
ccAddExternalFunctionForPlugin("AudioClip::PlayFrom^3", (void*)AudioClip_PlayFrom);
ccAddExternalFunctionForPlugin("AudioClip::PlayQueued^2", (void*)AudioClip_PlayQueued);
ccAddExternalFunctionForPlugin("AudioClip::Stop^0", (void*)AudioClip_Stop);
ccAddExternalFunctionForPlugin("AudioClip::get_FileType", (void*)AudioClip_GetFileType);
ccAddExternalFunctionForPlugin("AudioClip::get_IsAvailable", (void*)AudioClip_GetIsAvailable);
ccAddExternalFunctionForPlugin("AudioClip::get_Type", (void*)AudioClip_GetType);
}

View file

@ -0,0 +1,32 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__AUDIOCLIP_H
#define __AGS_EE_AC__AUDIOCLIP_H
#include "ac/dynobj/scriptaudioclip.h"
#include "ac/dynobj/scriptaudiochannel.h"
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);
#endif // __AGS_EE_AC__AUDIOCLIP_H

View file

@ -0,0 +1,501 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/button.h"
#include "ac/common.h"
#include "ac/gui.h"
#include "ac/view.h"
#include "ac/gamesetupstruct.h"
#include "ac/global_translation.h"
#include "ac/string.h"
#include "ac/viewframe.h"
#include "debug/debug_log.h"
#include "gui/animatingguibutton.h"
#include "gui/guimain.h"
using namespace AGS::Common;
extern GameSetupStruct game;
extern ViewStruct*views;
// *** BUTTON FUNCTIONS
AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
int numAnimButs;
void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat) {
int guin = butt->ParentId;
int objn = butt->Id;
if ((view < 1) || (view > game.numviews))
quit("!AnimateButton: invalid view specified");
view--;
if ((loop < 0) || (loop >= views[view].numLoops))
quit("!AnimateButton: invalid loop specified for view");
// if it's already animating, stop it
FindAndRemoveButtonAnimation(guin, objn);
if (numAnimButs >= MAX_ANIMATING_BUTTONS)
quit("!AnimateButton: too many animating GUI buttons at once");
int buttonId = guis[guin].GetControlID(objn);
guibuts[buttonId].PushedImage = 0;
guibuts[buttonId].MouseOverImage = 0;
animbuts[numAnimButs].ongui = guin;
animbuts[numAnimButs].onguibut = objn;
animbuts[numAnimButs].buttonid = buttonId;
animbuts[numAnimButs].view = view;
animbuts[numAnimButs].loop = loop;
animbuts[numAnimButs].speed = speed;
animbuts[numAnimButs].repeat = repeat;
animbuts[numAnimButs].frame = -1;
animbuts[numAnimButs].wait = 0;
numAnimButs++;
// launch into the first frame
if (UpdateAnimatingButton(numAnimButs - 1))
{
debug_script_warn("AnimateButton: no frames to animate");
StopButtonAnimation(numAnimButs - 1);
}
}
const char* Button_GetText_New(GUIButton *butt) {
return CreateNewScriptString(butt->GetText());
}
void Button_GetText(GUIButton *butt, char *buffer) {
strcpy(buffer, butt->GetText());
}
void Button_SetText(GUIButton *butt, const char *newtx) {
newtx = get_translation(newtx);
if (strcmp(butt->GetText(), newtx)) {
guis_need_update = 1;
butt->SetText(newtx);
}
}
void Button_SetFont(GUIButton *butt, int newFont) {
if ((newFont < 0) || (newFont >= game.numfonts))
quit("!Button.Font: invalid font number.");
if (butt->Font != newFont) {
butt->Font = newFont;
guis_need_update = 1;
}
}
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);
guis_need_update = 1;
}
}
int Button_GetGraphic(GUIButton *butt) {
// return currently displayed pic
if (butt->CurrentImage < 0)
return butt->Image;
return butt->CurrentImage;
}
int Button_GetMouseOverGraphic(GUIButton *butt) {
return butt->MouseOverImage;
}
void Button_SetMouseOverGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d mouseover set to slot %d", guil->ParentId, guil->Id, slotn);
if ((guil->IsMouseOver != 0) && (guil->IsPushed == 0))
guil->CurrentImage = slotn;
guil->MouseOverImage = slotn;
guis_need_update = 1;
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
int Button_GetNormalGraphic(GUIButton *butt) {
return butt->Image;
}
void Button_SetNormalGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d normal set to slot %d", guil->ParentId, guil->Id, slotn);
// normal pic - update if mouse is not over, or if there's no MouseOverImage
if (((guil->IsMouseOver == 0) || (guil->MouseOverImage < 1)) && (guil->IsPushed == 0))
guil->CurrentImage = slotn;
guil->Image = slotn;
// update the clickable area to the same size as the graphic
guil->Width = game.SpriteInfos[slotn].Width;
guil->Height = game.SpriteInfos[slotn].Height;
guis_need_update = 1;
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
int Button_GetPushedGraphic(GUIButton *butt) {
return butt->PushedImage;
}
void Button_SetPushedGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d pushed set to slot %d", guil->ParentId, guil->Id, slotn);
if (guil->IsPushed)
guil->CurrentImage = slotn;
guil->PushedImage = slotn;
guis_need_update = 1;
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;
guis_need_update = 1;
}
}
extern AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
extern int numAnimButs;
// ** start animating buttons code
// returns 1 if animation finished
int UpdateAnimatingButton(int bu) {
if (animbuts[bu].wait > 0) {
animbuts[bu].wait--;
return 0;
}
ViewStruct *tview = &views[animbuts[bu].view];
animbuts[bu].frame++;
if (animbuts[bu].frame >= tview->loops[animbuts[bu].loop].numFrames)
{
if (tview->loops[animbuts[bu].loop].RunNextLoop()) {
// go to next loop
animbuts[bu].loop++;
animbuts[bu].frame = 0;
}
else if (animbuts[bu].repeat) {
animbuts[bu].frame = 0;
// multi-loop anim, go back
while ((animbuts[bu].loop > 0) &&
(tview->loops[animbuts[bu].loop - 1].RunNextLoop()))
animbuts[bu].loop--;
}
else
return 1;
}
CheckViewFrame(animbuts[bu].view, animbuts[bu].loop, animbuts[bu].frame);
// update the button's image
guibuts[animbuts[bu].buttonid].Image = tview->loops[animbuts[bu].loop].frames[animbuts[bu].frame].pic;
guibuts[animbuts[bu].buttonid].CurrentImage = guibuts[animbuts[bu].buttonid].Image;
guibuts[animbuts[bu].buttonid].PushedImage = 0;
guibuts[animbuts[bu].buttonid].MouseOverImage = 0;
guis_need_update = 1;
animbuts[bu].wait = animbuts[bu].speed + tview->loops[animbuts[bu].loop].frames[animbuts[bu].frame].speed;
return 0;
}
void StopButtonAnimation(int idxn) {
numAnimButs--;
for (int aa = idxn; aa < numAnimButs; aa++) {
animbuts[aa] = animbuts[aa + 1];
}
}
// Returns the index of the AnimatingGUIButton object corresponding to the
// given button ID; returns -1 if no such animation exists
int FindAnimatedButton(int guin, int objn)
{
for (int i = 0; i < numAnimButs; ++i)
{
if (animbuts[i].ongui == guin && animbuts[i].onguibut == objn)
return i;
}
return -1;
}
void FindAndRemoveButtonAnimation(int guin, int objn)
{
int idx = FindAnimatedButton(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 FindAnimatedButton(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 = FindAnimatedButton(butt->ParentId, butt->Id);
return idx >= 0 ? animbuts[idx].view + 1 : 0;
}
int Button_GetAnimLoop(GUIButton *butt)
{
int idx = FindAnimatedButton(butt->ParentId, butt->Id);
return idx >= 0 ? animbuts[idx].loop : 0;
}
int Button_GetAnimFrame(GUIButton *butt)
{
int idx = FindAnimatedButton(butt->ParentId, butt->Id);
return idx >= 0 ? 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;
guis_need_update = 1;
}
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
#include "debug/out.h"
#include "script/script_api.h"
#include "script/script_runtime.h"
#include "ac/dynobj/scriptstring.h"
extern ScriptString myScriptStringImpl;
// void | GUIButton *butt, int view, int loop, int speed, int repeat
RuntimeScriptValue Sc_Button_Animate(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
API_OBJCALL_VOID_PINT4(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, 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_GetAnimating(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_GetFrame(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
API_OBJCALL_INT(GUIButton, Button_GetAnimFrame);
}
RuntimeScriptValue Sc_Button_GetLoop(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
API_OBJCALL_INT(GUIButton, Button_GetAnimLoop);
}
RuntimeScriptValue Sc_Button_GetView(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
API_OBJCALL_INT(GUIButton, Button_GetAnimView);
}
void RegisterButtonAPI()
{
ccAddExternalObjectFunction("Button::Animate^4", Sc_Button_Animate);
ccAddExternalObjectFunction("Button::Click^1", Sc_Button_Click);
ccAddExternalObjectFunction("Button::GetText^1", Sc_Button_GetText);
ccAddExternalObjectFunction("Button::SetText^1", Sc_Button_SetText);
ccAddExternalObjectFunction("Button::get_TextAlignment", Sc_Button_GetTextAlignment);
ccAddExternalObjectFunction("Button::set_TextAlignment", Sc_Button_SetTextAlignment);
ccAddExternalObjectFunction("Button::get_Animating", Sc_Button_GetAnimating);
ccAddExternalObjectFunction("Button::get_ClipImage", Sc_Button_GetClipImage);
ccAddExternalObjectFunction("Button::set_ClipImage", Sc_Button_SetClipImage);
ccAddExternalObjectFunction("Button::get_Font", Sc_Button_GetFont);
ccAddExternalObjectFunction("Button::set_Font", Sc_Button_SetFont);
ccAddExternalObjectFunction("Button::get_Frame", Sc_Button_GetFrame);
ccAddExternalObjectFunction("Button::get_Graphic", Sc_Button_GetGraphic);
ccAddExternalObjectFunction("Button::get_Loop", Sc_Button_GetLoop);
ccAddExternalObjectFunction("Button::get_MouseOverGraphic", Sc_Button_GetMouseOverGraphic);
ccAddExternalObjectFunction("Button::set_MouseOverGraphic", Sc_Button_SetMouseOverGraphic);
ccAddExternalObjectFunction("Button::get_NormalGraphic", Sc_Button_GetNormalGraphic);
ccAddExternalObjectFunction("Button::set_NormalGraphic", Sc_Button_SetNormalGraphic);
ccAddExternalObjectFunction("Button::get_PushedGraphic", Sc_Button_GetPushedGraphic);
ccAddExternalObjectFunction("Button::set_PushedGraphic", Sc_Button_SetPushedGraphic);
ccAddExternalObjectFunction("Button::get_Text", Sc_Button_GetText_New);
ccAddExternalObjectFunction("Button::set_Text", Sc_Button_SetText);
ccAddExternalObjectFunction("Button::get_TextColor", Sc_Button_GetTextColor);
ccAddExternalObjectFunction("Button::set_TextColor", Sc_Button_SetTextColor);
ccAddExternalObjectFunction("Button::get_View", Sc_Button_GetView);
/* ----------------------- Registering unsafe exports for plugins -----------------------*/
ccAddExternalFunctionForPlugin("Button::Animate^4", (void*)Button_Animate);
ccAddExternalFunctionForPlugin("Button::GetText^1", (void*)Button_GetText);
ccAddExternalFunctionForPlugin("Button::SetText^1", (void*)Button_SetText);
ccAddExternalFunctionForPlugin("Button::get_ClipImage", (void*)Button_GetClipImage);
ccAddExternalFunctionForPlugin("Button::set_ClipImage", (void*)Button_SetClipImage);
ccAddExternalFunctionForPlugin("Button::get_Font", (void*)Button_GetFont);
ccAddExternalFunctionForPlugin("Button::set_Font", (void*)Button_SetFont);
ccAddExternalFunctionForPlugin("Button::get_Graphic", (void*)Button_GetGraphic);
ccAddExternalFunctionForPlugin("Button::get_MouseOverGraphic", (void*)Button_GetMouseOverGraphic);
ccAddExternalFunctionForPlugin("Button::set_MouseOverGraphic", (void*)Button_SetMouseOverGraphic);
ccAddExternalFunctionForPlugin("Button::get_NormalGraphic", (void*)Button_GetNormalGraphic);
ccAddExternalFunctionForPlugin("Button::set_NormalGraphic", (void*)Button_SetNormalGraphic);
ccAddExternalFunctionForPlugin("Button::get_PushedGraphic", (void*)Button_GetPushedGraphic);
ccAddExternalFunctionForPlugin("Button::set_PushedGraphic", (void*)Button_SetPushedGraphic);
ccAddExternalFunctionForPlugin("Button::get_Text", (void*)Button_GetText_New);
ccAddExternalFunctionForPlugin("Button::set_Text", (void*)Button_SetText);
ccAddExternalFunctionForPlugin("Button::get_TextColor", (void*)Button_GetTextColor);
ccAddExternalFunctionForPlugin("Button::set_TextColor", (void*)Button_SetTextColor);
}

View file

@ -0,0 +1,47 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__BUTTON_H
#define __AGS_EE_AC__BUTTON_H
#include "gui/guibutton.h"
using AGS::Common::GUIButton;
void Button_Animate(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);
int UpdateAnimatingButton(int bu);
void StopButtonAnimation(int idxn);
void FindAndRemoveButtonAnimation(int guin, int objn);
#endif // __AGS_EE_AC__BUTTON_H

View file

@ -0,0 +1,39 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/cdaudio.h"
#include "platform/base/agsplatformdriver.h"
int use_cdplayer=0;
bool triedToUseCdAudioCommand = false;
int need_to_stop_cd=0;
int init_cd_player()
{
use_cdplayer=0;
return platform->InitializeCDPlayer();
}
int cd_manager(int cmdd,int datt)
{
if (!triedToUseCdAudioCommand)
{
triedToUseCdAudioCommand = true;
init_cd_player();
}
if (cmdd==0) return use_cdplayer;
if (use_cdplayer==0) return 0; // ignore other commands
return platform->CDPlayerCommand(cmdd, datt);
}

View file

@ -0,0 +1,31 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__CDAUDIO_H
#define __AGS_EE_AC__CDAUDIO_H
// 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) ;
#endif // __AGS_EE_AC__CDAUDIO_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,219 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__CHARACTER_H
#define __AGS_EE_AC__CHARACTER_H
#include "ac/characterinfo.h"
#include "ac/characterextras.h"
#include "ac/dynobj/scriptobject.h"
#include "ac/dynobj/scriptinvitem.h"
#include "ac/dynobj/scriptoverlay.h"
#include "game/viewport.h"
#include "util/geometry.h"
// **** CHARACTER: FUNCTIONS ****
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);
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_LockViewAlignedEx(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);
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);
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_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 Common { class Bitmap; } }
using namespace AGS; // FIXME later
void animate_character(CharacterInfo *chap, int loopn,int sppd,int rept, int noidleoverride = 0, int direction = 0, int sframe = 0);
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);
int find_nearest_walkable_area_within(int *xx, int *yy, int range, int step);
void find_nearest_walkable_area (int *xx, int *yy);
void walk_character(int chac,int tox,int toy,int ignwal, bool autoWalkAnims);
void FindReasonableLoopForCharacter(CharacterInfo *chap);
void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int direct, bool isWalk);
int is_valid_character(int newchar);
int wantMoveNow (CharacterInfo *chi, CharacterExtras *chex);
void setup_player_character(int charid);
void CheckViewFrameForCharacter(CharacterInfo *chi);
Common::Bitmap *GetCharacterImage(int charid, int *isFlipped);
CharacterInfo *GetCharacterAtScreen(int xx, int yy);
// 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 has walked onto character ww
int is_char_on_another (int sourceChar, int ww, int*fromxptr, int*cwidptr);
int my_getpixel(Common::Bitmap *blk, int x, int y);
// X and Y co-ordinates must be in 320x200 format
int check_click_on_character(int xx,int yy,int mood);
int is_pos_on_character(int xx,int yy);
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);
// 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);
extern CharacterInfo*playerchar;
extern CharacterExtras *charextra;
extern MoveList *mls;
extern int32_t _sc_PlayerCharPtr;
// order of loops to turn character in circle from down to down
extern int turnlooporder[8];
#endif // __AGS_EE_AC__CHARACTER_H

View file

@ -0,0 +1,35 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__CHARACTERCACHE_H
#define __AGS_EE_AC__CHARACTERCACHE_H
namespace AGS { namespace Common { class Bitmap; } }
using namespace AGS; // FIXME later
// stores cached info about the character
struct CharacterCache {
Common::Bitmap *image;
int sppic;
int scaling;
int inUse;
short tintredwas, tintgrnwas, tintbluwas, tintamntwas;
short lightlevwas, tintlightwas;
// no mirroredWas is required, since the code inverts the sprite number
};
#endif // __AGS_EE_AC__CHARACTERCACHE_H

View file

@ -0,0 +1,56 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/characterextras.h"
#include "util/stream.h"
using AGS::Common::Stream;
void CharacterExtras::ReadFromFile(Stream *in)
{
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();
}
void CharacterExtras::WriteToFile(Stream *out)
{
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);
}

View file

@ -0,0 +1,52 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__CHARACTEREXTRAS_H
#define __AGS_EE_AC__CHARACTEREXTRAS_H
#include "ac/runtime_defines.h"
// Forward declaration
namespace AGS { namespace Common { class Stream; } }
using namespace AGS; // FIXME later
struct CharacterExtras {
// UGLY UGLY UGLY!! The CharacterInfo struct size is fixed because it's
// used in the scripts, therefore overflowing stuff has to go here
short invorder[MAX_INVORDER];
short invorder_count;
// TODO: implement full AABB and keep updated, so that engine could rely on these cached values all time;
// TODO: consider having both fixed AABB and volatile one that changes with animation frame (unless you change how anims work)
short width;
short height;
short zoom;
short xwas;
short ywas;
short tint_r;
short tint_g;
short tint_b;
short tint_level;
short tint_light;
char process_idle_this_time;
char slow_move_counter;
short animwait;
void ReadFromFile(Common::Stream *in);
void WriteToFile(Common::Stream *out);
};
#endif // __AGS_EE_AC__CHARACTEREXTRAS_H

View file

@ -0,0 +1,508 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/characterinfo.h"
#include "ac/common.h"
#include "ac/gamesetupstruct.h"
#include "ac/character.h"
#include "ac/characterextras.h"
#include "ac/gamestate.h"
#include "ac/global_character.h"
#include "ac/math.h"
#include "ac/viewframe.h"
#include "debug/debug_log.h"
#include "game/roomstruct.h"
#include "main/maindefines_ex.h" // RETURN_CONTINUE
#include "main/update.h"
#include "media/audio/audio_system.h"
using namespace AGS::Common;
extern ViewStruct*views;
extern GameSetupStruct game;
extern int displayed_room;
extern GameState play;
extern int char_speaking;
extern RoomStruct thisroom;
extern unsigned int loopcounter;
#define Random __Rand
int CharacterInfo::get_effective_y() {
return y - z;
}
int CharacterInfo::get_baseline() {
if (baseline < 1)
return y;
return baseline;
}
int CharacterInfo::get_blocking_top() {
if (blocking_height > 0)
return y - blocking_height / 2;
return y - 2;
}
int CharacterInfo::get_blocking_bottom() {
// 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::UpdateMoveAndAnim(int &char_index, CharacterExtras *chex, int &numSheep, int *followingAsSheep)
{
int res;
if (on != 1) return;
// walking
res = update_character_walking(chex);
// [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
}
// Make sure it doesn't flash up a blue cup
if (view < 0) ;
else if (loop >= views[view].numLoops)
loop = 0;
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, numSheep, followingAsSheep, doing_nothing);
update_character_idle(chex, doing_nothing);
chex->process_idle_this_time = 0;
}
void CharacterInfo::UpdateFollowingExactlyCharacter()
{
x = game.chars[following].x;
y = game.chars[following].y;
z = game.chars[following].z;
room = game.chars[following].room;
prevroom = game.chars[following].prevroom;
int usebase = game.chars[following].get_baseline();
if (flags & CHF_BEHINDSHEPHERD)
baseline = usebase - 1;
else
baseline = usebase + 1;
}
int CharacterInfo::update_character_walking(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] >= views[view].numLoops) ||
(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 == 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++;
}
if (loop >= views[view].numLoops)
quitprintf("Unable to render character %d (%s) because loop %d does not exist in view %d", index_id, name, loop, view + 1);
// check don't overflow loop
int framesInLoop = views[view].loops[loop].numFrames;
if (frame > framesInLoop)
{
frame = 1;
if (framesInLoop < 2)
frame = 0;
if (framesInLoop < 1)
quitprintf("Unable to render character %d (%s) because there are no frames in loop %d", index_id, name, loop);
}
if (walking<1) {
chex->process_idle_this_time = 1;
doing_nothing=1;
walkwait=0;
chex->animwait = 0;
// use standing pic
Character_StopMoving(this);
frame = 0;
CheckViewFrameForCharacter(this);
}
else if (chex->animwait > 0) chex->animwait--;
else {
if (flags & CHF_ANTIGLIDE)
walkwaitcounter++;
if ((flags & CHF_MOVENOTWALK) == 0)
{
frame++;
if (frame >= views[view].loops[loop].numFrames)
{
// end of loop, so loop back round skipping the standing frame
frame = 1;
if (views[view].loops[loop].numFrames < 2)
frame = 0;
}
chex->animwait = views[view].loops[loop].frames[frame].speed + animspeed;
if (flags & CHF_ANTIGLIDE)
walkwait = chex->animwait;
else
walkwait = 0;
CheckViewFrameForCharacter(this);
}
}
doing_nothing = 0;
}
}
int CharacterInfo::update_character_animating(int &aa, int &doing_nothing)
{
// 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 == 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 ((char_speaking == aa) && (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 (play.speech_in_post_state ||
((play.messagetime >= 0) && (play.messagetime < play.close_mouth_speech_time)))
frame = 0;
if (frame != fraa) {
frame = fraa;
CheckViewFrameForCharacter(this);
}
//continue;
return RETURN_CONTINUE;
}
else {
int oldframe = frame;
if (animating & CHANIM_BACKWARDS) {
frame--;
if (frame < 0) {
// if the previous loop is a Run Next Loop one, go back to it
if ((loop > 0) &&
(views[view].loops[loop - 1].RunNextLoop())) {
loop --;
frame = views[view].loops[loop].numFrames - 1;
}
else if (animating & CHANIM_REPEAT) {
frame = views[view].loops[loop].numFrames - 1;
while (views[view].loops[loop].RunNextLoop()) {
loop++;
frame = views[view].loops[loop].numFrames - 1;
}
}
else {
frame++;
animating = 0;
}
}
}
else
frame++;
if ((aa == char_speaking) &&
(play.speech_in_post_state ||
((!play.speech_has_voice) &&
(play.close_mouth_speech_time > 0) &&
(play.messagetime < play.close_mouth_speech_time)))) {
// finished talking - stop animation
animating = 0;
frame = 0;
}
if (frame >= views[view].loops[loop].numFrames) {
if (views[view].loops[loop].RunNextLoop())
{
if (loop+1 >= views[view].numLoops)
quit("!Animating character tried to overrun last loop in view");
loop++;
frame=0;
}
else if ((animating & CHANIM_REPEAT)==0) {
animating=0;
frame--;
// 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;
}
}
}
else {
frame=0;
// if it's a multi-loop animation, go back to start
if (play.no_multiloop_repeat == 0) {
while ((loop > 0) &&
(views[view].loops[loop - 1].RunNextLoop()))
loop--;
}
}
}
wait = views[view].loops[loop].frames[frame].speed;
// idle anim doesn't have speed stored cos animating==0
if (idleleft < 0)
wait += animspeed+5;
else
wait += (animating >> 8) & 0x00ff;
if (frame != oldframe)
CheckViewFrameForCharacter(this);
}
}
return 0;
}
void CharacterInfo::update_character_follower(int &aa, int &numSheep, int *followingAsSheep, int &doing_nothing)
{
if ((following >= 0) && (followinfo == FOLLOW_ALWAYSONTOP)) {
// an always-on-top follow
if (numSheep >= MAX_SHEEP)
quit("too many sheep");
followingAsSheep[numSheep] = aa;
numSheep++;
}
// 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 ((game.chars[following].on == 0) || (on == 0)) ;
else if (room < 0) {
room ++;
if (room == 0) {
// appear in the new room
room = game.chars[following].room;
x = play.entered_at_x;
y = 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 != game.chars[following].room)
&& (game.chars[following].on == 0))
; // do nothing if the player isn't visible
else if (room != game.chars[following].room) {
prevroom = room;
room = game.chars[following].room;
if (room == displayed_room) {
// only move to the room-entered position if coming into
// the current room
if (play.entered_at_x > (thisroom.Width - 8)) {
x = thisroom.Width+8;
y = play.entered_at_y;
}
else if (play.entered_at_x < 8) {
x = -8;
y = play.entered_at_y;
}
else if (play.entered_at_y > (thisroom.Height - 8)) {
y = thisroom.Height+8;
x = play.entered_at_x;
}
else if (play.entered_at_y < thisroom.Edges.Top+8) {
y = thisroom.Edges.Top+1;
x = play.entered_at_x;
}
else {
// not at one of the edges
// delay for a few seconds to let the player move
room = -play.follow_change_room_timer;
}
if (room >= 0) {
walk_character(aa,play.entered_at_x,play.entered_at_y,1, true);
doing_nothing = 0;
}
}
}
else if (room != displayed_room) {
// if the characetr is following another character and
// neither is in the current room, don't try to move
}
else if ((abs(game.chars[following].x - x) > distaway+30) |
(abs(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,game.chars[following].x + goxoffs,
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 != 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 ((loopcounter%40==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 = 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 = rand() % maxLoops;
// don't select a loop which is a continuation of a previous one
} while ((useloop > 0) && (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,
animspeed+5,(idletime == 0) ? 1 : 0, 1);
// don't set Animating while the idle anim plays
animating = 0;
}
} // end do idle animation
}

View file

@ -0,0 +1,141 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <time.h>
#include "ac/datetime.h"
#include "platform/base/agsplatformdriver.h"
#include "script/runtimescriptvalue.h"
ScriptDateTime* DateTime_Now_Core() {
ScriptDateTime *sdt = new ScriptDateTime();
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
//
//=============================================================================
#include "debug/out.h"
#include "script/script_api.h"
#include "script/script_runtime.h"
// 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()
{
ccAddExternalStaticFunction("DateTime::get_Now", Sc_DateTime_Now);
ccAddExternalObjectFunction("DateTime::get_DayOfMonth", Sc_DateTime_GetDayOfMonth);
ccAddExternalObjectFunction("DateTime::get_Hour", Sc_DateTime_GetHour);
ccAddExternalObjectFunction("DateTime::get_Minute", Sc_DateTime_GetMinute);
ccAddExternalObjectFunction("DateTime::get_Month", Sc_DateTime_GetMonth);
ccAddExternalObjectFunction("DateTime::get_RawTime", Sc_DateTime_GetRawTime);
ccAddExternalObjectFunction("DateTime::get_Second", Sc_DateTime_GetSecond);
ccAddExternalObjectFunction("DateTime::get_Year", Sc_DateTime_GetYear);
/* ----------------------- Registering unsafe exports for plugins -----------------------*/
ccAddExternalFunctionForPlugin("DateTime::get_Now", (void*)DateTime_Now);
ccAddExternalFunctionForPlugin("DateTime::get_DayOfMonth", (void*)DateTime_GetDayOfMonth);
ccAddExternalFunctionForPlugin("DateTime::get_Hour", (void*)DateTime_GetHour);
ccAddExternalFunctionForPlugin("DateTime::get_Minute", (void*)DateTime_GetMinute);
ccAddExternalFunctionForPlugin("DateTime::get_Month", (void*)DateTime_GetMonth);
ccAddExternalFunctionForPlugin("DateTime::get_RawTime", (void*)DateTime_GetRawTime);
ccAddExternalFunctionForPlugin("DateTime::get_Second", (void*)DateTime_GetSecond);
ccAddExternalFunctionForPlugin("DateTime::get_Year", (void*)DateTime_GetYear);
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__DATETIME_H
#define __AGS_EE_AC__DATETIME_H
#include "ac/dynobj/scriptdatetime.h"
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);
#endif // __AGS_EE_AC__DATETIME_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__DIALOG_H
#define __AGS_EE_AC__DIALOG_H
#include <vector>
#include "ac/dynobj/scriptdialog.h"
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) ;
extern ScriptDialog *scrDialog;
#endif // __AGS_EE_AC__DIALOG_H

View file

@ -0,0 +1,332 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dialog.h"
#include "ac/dialogtopic.h"
#include "ac/dialogoptionsrendering.h"
#include "ac/gamestructdefines.h"
#include "debug/debug_log.h"
#include "script/runtimescriptvalue.h"
#include "ac/dynobj/cc_dialog.h"
extern DialogTopic *dialog;
extern CCDialog ccDynamicDialog;
// ** 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 &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 = dialog[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
//
//=============================================================================
#include "debug/out.h"
#include "script/script_api.h"
#include "script/script_runtime.h"
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, 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()
{
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::Update^0", Sc_DialogOptionsRendering_Update);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::RunActiveOption^0", Sc_DialogOptionsRendering_RunActiveOption);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_ActiveOptionID", Sc_DialogOptionsRendering_GetActiveOptionID);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_ActiveOptionID", Sc_DialogOptionsRendering_SetActiveOptionID);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_DialogToRender", Sc_DialogOptionsRendering_GetDialogToRender);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_Height", Sc_DialogOptionsRendering_GetHeight);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_Height", Sc_DialogOptionsRendering_SetHeight);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_ParserTextBoxX", Sc_DialogOptionsRendering_GetParserTextboxX);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_ParserTextBoxX", Sc_DialogOptionsRendering_SetParserTextboxX);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_ParserTextBoxY", Sc_DialogOptionsRendering_GetParserTextboxY);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_ParserTextBoxY", Sc_DialogOptionsRendering_SetParserTextboxY);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_ParserTextBoxWidth", Sc_DialogOptionsRendering_GetParserTextboxWidth);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_ParserTextBoxWidth", Sc_DialogOptionsRendering_SetParserTextboxWidth);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_Surface", Sc_DialogOptionsRendering_GetSurface);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_Width", Sc_DialogOptionsRendering_GetWidth);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_Width", Sc_DialogOptionsRendering_SetWidth);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_X", Sc_DialogOptionsRendering_GetX);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_X", Sc_DialogOptionsRendering_SetX);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_Y", Sc_DialogOptionsRendering_GetY);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_Y", Sc_DialogOptionsRendering_SetY);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::get_HasAlphaChannel", Sc_DialogOptionsRendering_GetHasAlphaChannel);
ccAddExternalObjectFunction("DialogOptionsRenderingInfo::set_HasAlphaChannel", Sc_DialogOptionsRendering_SetHasAlphaChannel);
/* ----------------------- Registering unsafe exports for plugins -----------------------*/
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_ActiveOptionID", (void*)DialogOptionsRendering_GetActiveOptionID);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_ActiveOptionID", (void*)DialogOptionsRendering_SetActiveOptionID);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_DialogToRender", (void*)DialogOptionsRendering_GetDialogToRender);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_Height", (void*)DialogOptionsRendering_GetHeight);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_Height", (void*)DialogOptionsRendering_SetHeight);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_ParserTextBoxX", (void*)DialogOptionsRendering_GetParserTextboxX);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_ParserTextBoxX", (void*)DialogOptionsRendering_SetParserTextboxX);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_ParserTextBoxY", (void*)DialogOptionsRendering_GetParserTextboxY);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_ParserTextBoxY", (void*)DialogOptionsRendering_SetParserTextboxY);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_ParserTextBoxWidth", (void*)DialogOptionsRendering_GetParserTextboxWidth);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_ParserTextBoxWidth", (void*)DialogOptionsRendering_SetParserTextboxWidth);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_Surface", (void*)DialogOptionsRendering_GetSurface);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_Width", (void*)DialogOptionsRendering_GetWidth);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_Width", (void*)DialogOptionsRendering_SetWidth);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_X", (void*)DialogOptionsRendering_GetX);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_X", (void*)DialogOptionsRendering_SetX);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::get_Y", (void*)DialogOptionsRendering_GetY);
ccAddExternalFunctionForPlugin("DialogOptionsRenderingInfo::set_Y", (void*)DialogOptionsRendering_SetY);
}

View file

@ -0,0 +1,45 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__DIALOGOPTIONSRENDERING_H
#define __AGS_EE_AC__DIALOGOPTIONSRENDERING_H
#include "ac/dynobj/scriptdialog.h"
#include "ac/dynobj/scriptdialogoptionsrendering.h"
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);
#endif // __AGS_EE_AC__DIALOGOPTIONSRENDERING_H

View file

@ -0,0 +1,832 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <math.h>
#include "ac/display.h"
#include "ac/common.h"
#include "font/agsfontrenderer.h"
#include "font/fonts.h"
#include "ac/character.h"
#include "ac/draw.h"
#include "ac/game.h"
#include "ac/gamesetupstruct.h"
#include "ac/gamestate.h"
#include "ac/global_audio.h"
#include "ac/global_game.h"
#include "ac/gui.h"
#include "ac/mouse.h"
#include "ac/overlay.h"
#include "ac/sys_events.h"
#include "ac/screenoverlay.h"
#include "ac/speech.h"
#include "ac/string.h"
#include "ac/system.h"
#include "ac/topbarsettings.h"
#include "debug/debug_log.h"
#include "gfx/blender.h"
#include "gui/guibutton.h"
#include "gui/guimain.h"
#include "main/game_run.h"
#include "platform/base/agsplatformdriver.h"
#include "ac/spritecache.h"
#include "gfx/gfx_util.h"
#include "util/string_utils.h"
#include "ac/mouse.h"
#include "media/audio/audio_system.h"
#include "ac/timer.h"
using namespace AGS::Common;
using namespace AGS::Common::BitmapHelper;
extern GameState play;
extern GameSetupStruct game;
extern int longestline;
extern AGSPlatformDriver *platform;
extern int loops_per_character;
extern SpriteCache spriteset;
int display_message_aschar=0;
TopBarSettings topBar;
struct DisplayVars
{
int lineheight; // font's height of single line
int linespacing; // font's line spacing
int fulltxtheight; // total height of all the text
} disp;
// 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
int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int usingfont, int asspch, int isThought, int allowShrink, bool overlayPositionFixed)
{
const bool use_speech_textwindow = (asspch < 0) && (game.options[OPT_SPEECHTYPE] >= 2);
const bool use_thought_gui = (isThought) && (game.options[OPT_THOUGHTGUI] > 0);
bool alphaChannel = false;
char todis[STD_BUFFER_SIZE];
snprintf(todis, STD_BUFFER_SIZE - 1, "%s", text);
int usingGui = -1;
if (use_speech_textwindow)
usingGui = play.speech_textwindow_gui;
else if (use_thought_gui)
usingGui = game.options[OPT_THOUGHTGUI];
int padding = get_textwindow_padding(usingGui);
int paddingScaled = get_fixed_pixel_size(padding);
int paddingDoubledScaled = get_fixed_pixel_size(padding * 2); // Just in case screen size does is not neatly divisible by 320x200
ensure_text_valid_for_font(todis, usingfont);
break_up_text_into_lines(todis, Lines, wii-2*padding, usingfont);
disp.lineheight = getfontheight_outlined(usingfont);
disp.linespacing= getfontspacing_outlined(usingfont);
disp.fulltxtheight = getheightoflines(usingfont, Lines.Count());
// AGS 2.x: If the screen is faded out, fade in again when displaying a message box.
if (!asspch && (loaded_game_file_version <= kGameVersion_272))
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 ((play.skip_until_char_stops >= 0) && (disp_type == DISPLAYTEXT_MESSAGEBOX))
render_graphics();
EndSkippingUntilCharStops();
if (topBar.wantIt) {
// ensure that the window is wide enough to display
// any top bar text
int topBarWid = wgettextwidth_compensate(topBar.text, topBar.font);
topBarWid += data_to_game_coord(play.top_bar_borderwidth + 2) * 2;
if (longestline < topBarWid)
longestline = topBarWid;
// the top bar should behave like DisplaySpeech wrt blocking
disp_type = DISPLAYTEXT_SPEECH;
}
if (asspch > 0) {
// update the all_buttons_disabled variable in advance
// of the adjust_x/y_for_guis calls
play.disabled_user_interface++;
update_gui_disabled_status();
play.disabled_user_interface--;
}
const Rect &ui_view = 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 (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 = 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;
int extraHeight = paddingDoubledScaled;
color_t text_color = MakeColor(15);
if (disp_type < DISPLAYTEXT_NORMALOVERLAY)
remove_screen_overlay(OVER_TEXTMSG); // remove any previous blocking texts
Bitmap *text_window_ds = BitmapHelper::CreateTransparentBitmap((wii > 0) ? wii : 2, disp.fulltxtheight + extraHeight, game.GetColorDepth());
// inform draw_text_window to free the old bitmap
const bool wantFreeScreenop = true;
//
// Creating displayed graphic
//
// may later change if usingGUI, needed to avoid changing original coordinates
int adjustedXX = xx;
int 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 = guis[usingGui].HasAlphaChannel();
}
}
else if ((ShouldAntiAliasText()) && (game.GetColorDepth() >= 24))
alphaChannel = true;
for (size_t ee=0;ee<Lines.Count();ee++) {
//int ttxp=wii/2 - wgettextwidth_compensate(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) &&
((game.options[OPT_SPEECHTYPE] >= 2) || (isThought)))
text_color = text_window_ds->GetCompatibleColor(guis[usingGui].FgColor);
else
text_color = text_window_ds->GetCompatibleColor(-asspch);
wouttext_aligned(text_window_ds, ttxleft, ttyp, oriwid, usingfont, text_color, Lines[ee], play.text_align);
}
else {
text_color = text_window_ds->GetCompatibleColor(asspch);
wouttext_aligned(text_window_ds, ttxleft, ttyp, wii, usingfont, text_color, Lines[ee], play.speech_text_align);
}
}
}
else {
int xoffs,yoffs, oriwid = wii - padding * 2;
draw_text_window_and_bar(&text_window_ds, wantFreeScreenop, &xoffs,&yoffs,&xx,&yy,&wii,&text_color);
if (game.options[OPT_TWCUSTOM] > 0)
{
alphaChannel = guis[game.options[OPT_TWCUSTOM]].HasAlphaChannel();
}
adjust_y_coordinate_for_text(&yoffs, usingfont);
for (size_t ee=0;ee<Lines.Count();ee++)
wouttext_aligned (text_window_ds, xoffs, yoffs + ee * disp.linespacing, oriwid, usingfont, text_color, Lines[ee], play.text_align);
}
int ovrtype = OVER_TEXTMSG;
if (disp_type == DISPLAYTEXT_NORMALOVERLAY) ovrtype=OVER_CUSTOM;
else if (disp_type >= OVER_CUSTOM) ovrtype = disp_type;
int nse = add_screen_overlay(xx, yy, ovrtype, text_window_ds, adjustedXX - xx, adjustedYY - yy, alphaChannel);
// we should not delete text_window_ds here, because it is now owned by Overlay
if (disp_type >= DISPLAYTEXT_NORMALOVERLAY) {
return screenover[nse].type;
}
//
// Wait for the blocking text to timeout or until skipped by another command
//
if (disp_type == DISPLAYTEXT_MESSAGEBOX) {
// If fast-forwarding, then skip immediately
if (play.fast_forward) {
remove_screen_overlay(OVER_TEXTMSG);
play.messagetime=-1;
return 0;
}
if (!play.mouse_cursor_hidden)
ags_domouse(DOMOUSE_ENABLE);
int countdown = GetTextDisplayTime (todis);
int skip_setting = user_to_internal_skip_speech((SkipSpeechStyle)play.skip_display);
// Loop until skipped
while (true) {
update_audio_system_on_game_loop();
render_graphics();
int mbut, mwheelz;
if (run_service_mb_controls(mbut, mwheelz) && mbut >= 0) {
check_skip_cutscene_mclick(mbut);
if (play.fast_forward)
break;
if (skip_setting & SKIP_MOUSECLICK && !play.IsIgnoringInput())
break;
}
int kp;
if (run_service_key_controls(kp)) {
check_skip_cutscene_keypress (kp);
if (play.fast_forward)
break;
if ((skip_setting & SKIP_KEYPRESS) && !play.IsIgnoringInput())
break;
}
update_polled_stuff_if_runtime();
if (play.fast_forward == 0)
{
WaitForNextFrame();
}
countdown--;
// Special behavior when coupled with a voice-over
if (play.speech_has_voice) {
// extend life of text if the voice hasn't finished yet
if (channel_is_playing(SCHAN_SPEECH) && (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))
{
play.SetIgnoreInput(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) && (play.fast_forward))
break;
}
if (!play.mouse_cursor_hidden)
ags_domouse(DOMOUSE_DISABLE);
remove_screen_overlay(OVER_TEXTMSG);
invalidate_screen();
}
else {
// if the speech does not time out, but we are skipping a cutscene,
// allow it to time out
if ((play.messagetime < 0) && (play.fast_forward))
play.messagetime = 2;
if (!overlayPositionFixed)
{
screenover[nse].positionRelativeToScreen = false;
VpPoint vpt = play.GetRoomViewport(0)->ScreenToRoom(screenover[nse].x, screenover[nse].y, false);
screenover[nse].x = vpt.first.X;
screenover[nse].y = vpt.first.Y;
}
GameLoopUntilNoOverlay();
}
play.messagetime=-1;
return 0;
}
void _display_at(int xx, int yy, int wii, const char *text, int disp_type, int asspch, int isThought, int allowShrink, bool overlayPositionFixed) {
int usingfont=FONT_NORMAL;
if (asspch) usingfont=FONT_SPEECH;
// TODO: _display_at may be called from _displayspeech, which can start
// and finalize voice speech on its own. Find out if we really need to
// keep track of this and not just stop voice regardless.
bool need_stop_speech = false;
EndSkippingUntilCharStops();
if (try_auto_play_speech(text, text, play.narrator_speech, true))
{// TODO: is there any need for this flag?
need_stop_speech = true;
}
_display_main(xx, yy, wii, text, disp_type, usingfont, asspch, isThought, allowShrink, overlayPositionFixed);
if (need_stop_speech)
stop_voice_speech();
}
bool try_auto_play_speech(const char *text, const char *&replace_text, int charid, bool blocking)
{
const char *src = text;
if (src[0] != '&')
return false;
int sndid = atoi(&src[1]);
while ((src[0] != ' ') & (src[0] != 0)) src++;
if (src[0] == ' ') src++;
if (sndid <= 0)
quit("DisplaySpeech: auto-voice symbol '&' not followed by valid integer");
replace_text = src; // skip voice tag
if (play_voice_speech(charid, sndid))
{
// if Voice Only, then blank out the text
if (play.want_speech == 2)
replace_text = " ";
return true;
}
return false;
}
// TODO: refactor this global variable out; currently it is set at the every get_translation call.
// Be careful: a number of Say/Display functions expect it to be set beforehand.
int source_text_length = -1;
int GetTextDisplayLength(const char *text)
{
int len = (int)strlen(text);
if ((text[0] == '&') && (play.unfactor_speech_from_textlength != 0))
{
// if there's an "&12 text" type line, remove "&12 " from the source length
size_t j = 0;
while ((text[j] != ' ') && (text[j] != 0))
j++;
j++;
len -= j;
}
return len;
}
int GetTextDisplayTime(const char *text, int canberel) {
int uselen = 0;
auto fpstimer = ::lround(get_current_fps());
// if it's background speech, make it stay relative to game speed
if ((canberel == 1) && (play.bgspeech_game_speed == 1))
fpstimer = 40;
if (source_text_length >= 0) {
// sync to length of original text, to make sure any animations
// and music sync up correctly
uselen = source_text_length;
source_text_length = -1;
}
else {
uselen = GetTextDisplayLength(text);
}
if (uselen <= 0)
return 0;
if (play.text_speed + play.text_speed_modifier <= 0)
quit("!Text speed is zero; unable to display text. Check your game.text_speed settings.");
// Store how many game loops per character of text
// This is calculated using a hard-coded 15 for the text speed,
// so that it's always the same no matter how fast the user
// can read.
loops_per_character = (((uselen/play.lipsync_speed)+1) * fpstimer) / uselen;
int textDisplayTimeInMS = ((uselen / (play.text_speed + play.text_speed_modifier)) + 1) * 1000;
if (textDisplayTimeInMS < play.text_min_display_time_ms)
textDisplayTimeInMS = play.text_min_display_time_ms;
return (textDisplayTimeInMS * fpstimer) / 1000;
}
bool ShouldAntiAliasText() {
return (game.options[OPT_ANTIALIASFONTS] != 0);
}
#if defined (AGS_FONTOUTLINE_MOREOPAQUE)
// TODO: was suggested by fernewelten, but it's unclear whether is necessary
// Make semi-transparent bits much more opaque
void wouttextxy_AutoOutline_Semitransparent2Opaque(Bitmap *map)
{
if (map->GetColorDepth() < 32)
return; // such maps don't feature partial transparency
size_t const width = map->GetWidth();
size_t const height = map->GetHeight();
for (size_t y = 0; y < height; y++)
{
int32 *sc_line = reinterpret_cast<int32 *>(map->GetScanLineForWriting(y));
for (size_t x = 0; x < width; x++)
{
int32 &px = sc_line[x];
int const transparency = geta(px);
if (0 < transparency && transparency < 255)
px = makeacol32(
getr32(px),
getg32(px),
getb32(px),
std::min(85 + transparency * 2, 255));
}
}
}
#endif
// Draw outline that is calculated from the text font, not derived from an outline font
void wouttextxy_AutoOutline(Bitmap *ds, size_t font, int32_t color, const char *texx, int &xxp, int &yyp)
{
int const thickness = game.fonts.at(font).AutoOutlineThickness;
auto const style = game.fonts.at(font).AutoOutlineStyle;
if (thickness <= 0)
return;
// 16-bit games should use 32-bit stencils to keep anti-aliasing working
int const ds_cd = ds->GetColorDepth();
bool const antialias = ds_cd >= 16 && 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);
size_t const t_width = wgettextwidth(texx, font);
size_t const t_height = wgettextheight(texx, font);
if (t_width == 0 || t_height == 0)
return;
Bitmap texx_stencil, outline_stencil;
texx_stencil.CreateTransparent(t_width, t_height, stencil_cd);
outline_stencil.CreateTransparent(t_width, t_height + 2 * thickness, stencil_cd);
if (outline_stencil.IsNull() || texx_stencil.IsNull())
return;
wouttextxy(&texx_stencil, 0, 0, font, color, texx);
#if defined (AGS_FONTOUTLINE_MOREOPAQUE)
wouttextxy_AutoOutline_Semitransparent2Opaque(texx_stencil);
#endif
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;
yyp += thickness;
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(Common::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(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) - (wgettextwidth_compensate(text, usingfont) / 2);
else if (align & kMAlignRight)
usexp = usexp + (oriwid - wgettextwidth_compensate(text, usingfont));
wouttext_outline(ds, usexp, yy, usingfont, text_color, (char *)text);
}
// Get outline's thickness addition to the font's width or height
int get_outline_padding(int font)
{
if (get_font_outline(font) == FONT_OUTLINE_AUTO) {
return get_font_outline_thickness(font) * 2;
}
return 0;
}
int getfontheight_outlined(int font)
{
return getfontheight(font) + get_outline_padding(font);
}
int getfontspacing_outlined(int font)
{
return use_default_linespacing(font) ?
getfontheight_outlined(font) :
getfontlinespacing(font);
}
int getfontlinegap(int font)
{
return getfontspacing_outlined(font) - getfontheight_outlined(font);
}
int getheightoflines(int font, int numlines)
{
return getfontspacing_outlined(font) * (numlines - 1) + getfontheight_outlined(font);
}
int wgettextwidth_compensate(const char *tex, int font)
{
return wgettextwidth(tex, font) + get_outline_padding(font);
}
void do_corner(Bitmap *ds, int sprn, int x, int y, int offx, int offy) {
if (sprn<0) return;
if (spriteset[sprn] == nullptr)
{
sprn = 0;
}
x = x + offx * game.SpriteInfos[sprn].Width;
y = y + offy * 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 ? guibuts[butid].Image : 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);
/* draw_color = ds->GetCompatibleColor(opts.tws.backcol); ds->FillRect(Rect(xx1,yy1,xx2,yy2);
draw_color = ds->GetCompatibleColor(opts.tws.ds->GetTextColor()); ds->DrawRect(Rect(xx1+1,yy1+1,xx2-1,yy2-1);*/
}
else {
if (loaded_game_file_version < kGameVersion_262) // < 2.62
{
// Color 0 wrongly shows as transparent instead of black
// From the changelog of 2.62:
// - Fixed text windows getting a black background if colour 0 was
// specified, rather than being transparent.
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);
int leftRightWidth = game.SpriteInfos[get_but_pic(iep,4)].Width;
int topBottomHeight = game.SpriteInfos[get_but_pic(iep,6)].Height;
if (iep->BgImage>0) {
if ((loaded_game_file_version <= kGameVersion_272) // 2.xx
&& (spriteset[iep->BgImage]->GetWidth() == 1)
&& (spriteset[iep->BgImage]->GetHeight() == 1)
&& (*((unsigned int*)spriteset[iep->BgImage]->GetData()) == 0x00FF00FF))
{
// Don't draw fully transparent dummy GUI backgrounds
}
else
{
// 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 += game.SpriteInfos[iep->BgImage].Height;
}
bgoffsx += game.SpriteInfos[iep->BgImage].Width;
}
// return to normal clipping rectangle
ds->SetClip(Rect(0, 0, ds->GetWidth() - 1, ds->GetHeight() - 1));
}
}
int uu;
for (uu=yy1;uu <= yy2;uu+= 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
}
for (uu=xx1;uu <= xx2;uu+=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
}
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 (!guis[twgui].IsTextWindow())
quit("!GUI set as text window but is not actually a text window GUI");
int borwid = game.SpriteInfos[get_but_pic(&guis[twgui], 4)].Width +
game.SpriteInfos[get_but_pic(&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 (!guis[twgui].IsTextWindow())
quit("!GUI set as text window but is not actually a text window GUI");
return game.SpriteInfos[get_but_pic(&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 = game.options[OPT_TWCUSTOM];
if (ifnum > 0 && ifnum < game.numgui)
result = 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) {
Bitmap *ds = *text_window_ds;
if (ifnum < 0)
ifnum = 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 >= game.numgui)
quitprintf("!Invalid GUI %d specified as text window (total GUIs: %d)", ifnum, game.numgui);
if (!guis[ifnum].IsTextWindow())
quit("!GUI set as text window but is not actually a text window GUI");
int tbnum = get_but_pic(&guis[ifnum], 0);
wii[0] += get_textwindow_border_width (ifnum);
xx[0]-=game.SpriteInfos[tbnum].Width;
yy[0]-=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)+ game.SpriteInfos[tbnum].Height*2,game.GetColorDepth());
ds = *text_window_ds;
int xoffs=game.SpriteInfos[tbnum].Width,yoffs= game.SpriteInfos[tbnum].Height;
draw_button_background(ds, xoffs,yoffs,(ds->GetWidth() - xoffs) - 1,(ds->GetHeight() - yoffs) - 1,&guis[ifnum]);
if (set_text_color)
*set_text_color = ds->GetCompatibleColor(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) {
draw_text_window(text_window_ds, should_free_ds, xins, yins, xx, yy, wii, set_text_color, ovrheight, ifnum);
if ((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() + topBar.height, game.GetColorDepth());
newScreenop->Blit(ds, 0, 0, 0, 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(play.top_bar_backcolor);
ds->FillRect(Rect(0, 0, ds->GetWidth() - 1, topBar.height - 1), draw_color);
if (play.top_bar_backcolor != play.top_bar_bordercolor) {
// draw the border
draw_color = ds->GetCompatibleColor(play.top_bar_bordercolor);
for (int j = 0; j < data_to_game_coord(play.top_bar_borderwidth); j++)
ds->DrawRect(Rect(j, j, ds->GetWidth() - (j + 1), topBar.height - (j + 1)), draw_color);
}
// draw the text
int textx = (ds->GetWidth() / 2) - wgettextwidth_compensate(topBar.text, topBar.font) / 2;
color_t text_color = ds->GetCompatibleColor(play.top_bar_textcolor);
wouttext_outline(ds, textx, play.top_bar_borderwidth + get_fixed_pixel_size(1), topBar.font, text_color, topBar.text);
// don't draw it next time
topBar.wantIt = 0;
// adjust the text Y position
yins[0] += topBar.height;
}
else if (topBar.wantIt)
topBar.wantIt = 0;
}

View file

@ -0,0 +1,80 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__DISPLAY_H
#define __AGS_EE_AC__DISPLAY_H
#include "gui/guimain.h"
using AGS::Common::GUIMain;
// options for 'disp_type' parameter
#define DISPLAYTEXT_SPEECH 0
#define DISPLAYTEXT_MESSAGEBOX 1
#define DISPLAYTEXT_NORMALOVERLAY 2
// also accepts explicit overlay ID >= OVER_CUSTOM
int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int usingfont, int asspch, int isThought, int allowShrink, bool overlayPositionFixed);
void _display_at(int xx, int yy, int wii, const char *text, int disp_type, int asspch, int isThought, int allowShrink, bool overlayPositionFixed);
// 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, bool blocking);
bool ShouldAntiAliasText();
// 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(Common::Bitmap *ds, int xxp, int yyp, int usingfont, color_t text_color, const char *texx);
void wouttext_aligned (Common::Bitmap *ds, int usexp, int yy, int oriwid, int usingfont, color_t text_color, const char *text, HorAlignment align);
// TODO: GUI classes located in Common library do not make use of outlining,
// need to find a way to make all code use same functions.
// Get the maximal height of the given font, with corresponding outlining
int getfontheight_outlined(int font);
// Get line spacing for the given font, with possible outlining in mind
int getfontspacing_outlined(int font);
// Get the distance between bottom one one line and top of the next line (may be negative!)
int getfontlinegap(int font);
// Gets the total maximal height of the given number of lines printed with the given font
int getheightoflines(int font, int numlines);
// Get the maximal width of the given font, with corresponding outlining
int wgettextwidth_compensate(const char *tex, int font);
void do_corner(Common::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(Common::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(Common::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(Common::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);
// The efficient length of the last source text prepared for display
extern int source_text_length;
#endif // __AGS_EE_AC__DISPLAY_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,175 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__DRAW_H
#define __AGS_EE_AC__DRAW_H
#include <memory>
#include "core/types.h"
#include "ac/common_defines.h"
#include "gfx/gfx_def.h"
#include "util/wgt2allg.h"
namespace AGS
{
namespace Common
{
class Bitmap;
typedef std::shared_ptr<Common::Bitmap> PBitmap;
}
namespace Engine { class IDriverDependantBitmap; }
}
using namespace AGS; // FIXME later
#define IS_ANTIALIAS_SPRITES usetup.enable_antialiasing && (play.disable_antialiasing == 0)
// [IKM] WARNING: these definitions has to be made AFTER Allegro headers
// were included, because they override few Allegro function names;
// otherwise Allegro headers should not be included at all to the same
// code unit which uses these defines.
#define getr32(xx) ((xx >> _rgb_r_shift_32) & 0xFF)
#define getg32(xx) ((xx >> _rgb_g_shift_32) & 0xFF)
#define getb32(xx) ((xx >> _rgb_b_shift_32) & 0xFF)
#define geta32(xx) ((xx >> _rgb_a_shift_32) & 0xFF)
#define makeacol32(r,g,b,a) ((r << _rgb_r_shift_32) | (g << _rgb_g_shift_32) | (b << _rgb_b_shift_32) | (a << _rgb_a_shift_32))
struct CachedActSpsData {
int xWas, yWas;
int baselineWas;
int isWalkBehindHere;
int valid;
};
// 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 drawing resources upon entering new room
void init_room_drawdata();
// Disposes resources related to the current drawing methods
void dispose_draw_method();
// Disposes any temporary resources on leaving current room
void dispose_room_drawdata();
// 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);
// 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();
void invalidate_cached_walkbehinds();
// Avoid freeing and reallocating the memory if possible
Common::Bitmap *recycle_bitmap(Common::Bitmap *bimp, int coldep, int wid, int hit, bool make_transparent = false);
Engine::IDriverDependantBitmap* recycle_ddb_bitmap(Engine::IDriverDependantBitmap *bimp, Common::Bitmap *source, bool hasAlpha = false, bool opaque = false);
// 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();
void add_to_sprite_list(Engine::IDriverDependantBitmap* spp, int xx, int yy, int baseline, int trans, int sprNum, bool isWalkBehind = false);
void tint_image (Common::Bitmap *g, Common::Bitmap *source, int red, int grn, int blu, int light_level, int luminance=255);
void draw_sprite_support_alpha(Common::Bitmap *ds, bool ds_has_alpha, int xpos, int ypos, Common::Bitmap *image, bool src_has_alpha,
Common::BlendMode blend_mode = Common::kBlendMode_Alpha, int alpha = 0xFF);
void draw_sprite_slot_support_alpha(Common::Bitmap *ds, bool ds_has_alpha, int xpos, int ypos, int src_slot,
Common::BlendMode blend_mode = Common::kBlendMode_Alpha, int alpha = 0xFF);
void draw_gui_sprite(Common::Bitmap *ds, int pic, int x, int y, bool use_alpha, Common::BlendMode blend_mode);
void draw_gui_sprite_v330(Common::Bitmap *ds, int pic, int x, int y, bool use_alpha = true, Common::BlendMode blend_mode = Common::kBlendMode_Alpha);
// Render game on screen
void render_to_screen();
// Callbacks for the graphics driver
void draw_game_screen_callback();
void GfxDriverOnInitCallback(void *data);
bool GfxDriverNullSpriteCallback(int x, int y);
void putpixel_compensate (Common::Bitmap *g, int xx,int yy, int col);
// create the actsps[aa] image with the object drawn correctly
// returns 1 if nothing at all has changed and actsps is still
// intact from last time; 0 otherwise
int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysUseSoftware);
void clear_letterbox_borders();
void draw_and_invalidate_text(Common::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).
extern AGS_INLINE int get_fixed_pixel_size(int pixels);
// coordinate conversion data,script ---> final game resolution
extern AGS_INLINE int data_to_game_coord(int coord);
extern AGS_INLINE void data_to_game_coords(int *x, int *y);
extern AGS_INLINE void data_to_game_round_up(int *x, int *y);
// coordinate conversion final game resolution ---> data,script
extern AGS_INLINE int game_to_data_coord(int coord);
extern AGS_INLINE void game_to_data_coords(int &x, int &y);
extern AGS_INLINE int game_to_data_round_up(int coord);
// convert contextual data coordinates to final game resolution
extern AGS_INLINE void ctx_data_to_game_coord(int &x, int &y, bool hires_ctx);
extern AGS_INLINE void ctx_data_to_game_size(int &x, int &y, bool hires_ctx);
extern AGS_INLINE int ctx_data_to_game_size(int size, bool hires_ctx);
extern AGS_INLINE 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 AGS_INLINE void defgame_to_finalgame_coords(int &x, int &y);
// Checks if the bitmap needs to be converted and **deletes original** if a new bitmap
// had to be created (by default).
// TODO: this helper function was meant to remove bitmap deletion from the GraphicsDriver's
// implementations while keeping code changes to minimum. The proper solution would probably
// be to use shared pointers when storing Bitmaps, or make Bitmap reference-counted object.
Common::Bitmap *ReplaceBitmapWithSupportedFormat(Common::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.
Common::Bitmap *PrepareSpriteForUse(Common::Bitmap *bitmap, bool has_alpha);
// Same as above, but compatible for std::shared_ptr.
Common::PBitmap PrepareSpriteForUse(Common::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.
Common::Bitmap *CopyScreenIntoBitmap(int width, int height, bool at_native_res = false);
#endif // __AGS_EE_AC__DRAW_H

View file

@ -0,0 +1,491 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// 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 perfomance 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 <string.h>
#include <vector>
#include "ac/draw_software.h"
#include "gfx/bitmap.h"
#include "util/scaling.h"
using namespace AGS::Common;
using namespace AGS::Engine;
// 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();
};
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;
}
// Dirty rects for the main viewport background (black screen);
// these are used when the room viewport does not cover whole screen,
// so that we know when to paint black after mouse cursor and gui.
DirtyRects BlackRects;
// Dirty rects object for the single room camera
std::vector<DirtyRects> RoomCamRects;
// Saved room camera offsets to know if we must invalidate whole surface.
// TODO: if we support rotation then we also need to compare full transform!
std::vector<std::pair<int, int>> RoomCamPositions;
void dispose_invalid_regions(bool /* room_only */)
{
RoomCamRects.clear();
RoomCamPositions.clear();
}
void init_invalid_regions(int view_index, const Size &surf_size, const Rect &viewport)
{
if (view_index < 0)
{
BlackRects.Init(surf_size, viewport);
}
else
{
if (RoomCamRects.size() <= (size_t)view_index)
{
RoomCamRects.resize(view_index + 1);
RoomCamPositions.resize(view_index + 1);
}
RoomCamRects[view_index].Init(surf_size, viewport);
RoomCamPositions[view_index] = std::make_pair(-1000, -1000);
}
}
void delete_invalid_regions(int view_index)
{
if (view_index >= 0)
{
RoomCamRects.erase(RoomCamRects.begin() + view_index);
RoomCamPositions.erase(RoomCamPositions.begin() + view_index);
}
}
void set_invalidrects_cameraoffs(int view_index, int x, int y)
{
if (view_index < 0)
{
BlackRects.SetSurfaceOffsets(x, y);
return;
}
else
{
RoomCamRects[view_index].SetSurfaceOffsets(x, y);
}
int &posxwas = RoomCamPositions[view_index].first;
int &posywas = 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 : RoomCamRects)
{
if (!IsRectInsideRect(rects.Viewport, BlackRects.Viewport))
BlackRects.NumDirtyRegions = WHOLESCREENDIRTY;
rects.NumDirtyRegions = WHOLESCREENDIRTY;
}
}
void invalidate_all_camera_rects(int view_index)
{
if (view_index < 0)
return;
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;
}
int a;
const Size &surfsz = rects.SurfaceSize;
if (x1 >= surfsz.Width) x1 = surfsz.Width - 1;
if (y1 >= surfsz.Height) y1 = surfsz.Height - 1;
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;
if (x2 < 0) x2 = 0;
if (y2 < 0) y2 = 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;
int tleft, tright;
// find the nearest span, and enlarge that to include this rect
for (s = 0; s < dirtyRow[a].numSpans; s++) {
tleft = dirtyRow[a].span[s].x1 - x2;
if ((tleft > 0) && (tleft < nearestDist)) {
nearestDist = tleft;
nearestWas = s;
extendLeft = 1;
}
tright = x1 - dirtyRow[a].span[s].x2;
if ((tright > 0) && (tright < nearestDist)) {
nearestDist = tright;
nearestWas = s;
extendLeft = 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, 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
{
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)
{
for (auto &rects : RoomCamRects)
invalidate_rect_ds(rects, x1, y1, x2, y2, in_room);
}
// 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()) && (ds->IsMemoryBitmap()))
{
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 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 (!BlackRects.IsInit())
return;
update_invalid_region(ds, (color_t)0, BlackRects);
BlackRects.Reset();
}
void update_room_invreg_and_reset(int view_index, Bitmap *ds, Bitmap *src, bool no_transform)
{
if (view_index < 0 || RoomCamRects.size() == 0)
return;
update_invalid_region(ds, src, RoomCamRects[view_index], no_transform);
RoomCamRects[view_index].Reset();
}

View file

@ -0,0 +1,46 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// Software drawing component. Optimizes drawing for software renderer using
// dirty rectangles technique.
//
//=============================================================================
#ifndef __AGS_EE_AC__DRAWSOFTWARE_H
#define __AGS_EE_AC__DRAWSOFTWARE_H
#include "gfx/bitmap.h"
#include "gfx/ddb.h"
#include "util/geometry.h"
// 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);
void invalidate_rect_ds(int x1, int y1, int x2, int y2, bool in_room);
// Paints the black screen background in the regions marked as dirty
void update_black_invreg_and_reset(AGS::Common::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::Common::Bitmap *ds, AGS::Common::Bitmap *src, bool no_transform);
#endif // __AGS_EE_AC__DRAWSOFTWARE_H

View file

@ -0,0 +1,694 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/draw.h"
#include "ac/drawingsurface.h"
#include "ac/common.h"
#include "ac/charactercache.h"
#include "ac/display.h"
#include "ac/game.h"
#include "ac/gamesetupstruct.h"
#include "ac/gamestate.h"
#include "ac/global_translation.h"
#include "ac/objectcache.h"
#include "ac/roomobject.h"
#include "ac/roomstatus.h"
#include "ac/string.h"
#include "ac/walkbehind.h"
#include "debug/debug_log.h"
#include "font/fonts.h"
#include "gui/guimain.h"
#include "ac/spritecache.h"
#include "script/runtimescriptvalue.h"
#include "gfx/gfx_def.h"
#include "gfx/gfx_util.h"
using namespace AGS::Common;
using namespace AGS::Engine;
extern GameSetupStruct game;
extern GameState play;
extern RoomStatus*croom;
extern RoomObject*objs;
extern CharacterCache *charcache;
extern ObjectCache objcache[MAX_ROOM_OBJECTS];
extern SpriteCache spriteset;
extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
// ** SCRIPT DRAWINGSURFACE OBJECT
void DrawingSurface_Release(ScriptDrawingSurface* sds)
{
if (sds->roomBackgroundNumber >= 0)
{
if (sds->modified)
{
if (sds->roomBackgroundNumber == play.bg_frame)
{
invalidate_screen();
mark_current_background_dirty();
}
play.raw_modified[sds->roomBackgroundNumber] = 1;
}
sds->roomBackgroundNumber = -1;
}
if (sds->roomMaskType > kRoomAreaNone)
{
if (sds->roomMaskType == kRoomAreaWalkBehind)
{
recache_walk_behinds();
}
sds->roomMaskType = kRoomAreaNone;
}
if (sds->dynamicSpriteNumber >= 0)
{
if (sds->modified)
{
int tt;
// force a refresh of any cached object or character images
if (croom != nullptr)
{
for (tt = 0; tt < croom->numobj; tt++)
{
if (objs[tt].num == sds->dynamicSpriteNumber)
objcache[tt].sppic = -31999;
}
}
for (tt = 0; tt < game.numcharacters; tt++)
{
if (charcache[tt].sppic == sds->dynamicSpriteNumber)
charcache[tt].sppic = -31999;
}
for (tt = 0; tt < game.numgui; tt++)
{
if ((guis[tt].BgImage == sds->dynamicSpriteNumber) &&
(guis[tt].IsDisplayed()))
{
guis_need_update = 1;
break;
}
}
}
sds->dynamicSpriteNumber = -1;
}
if (sds->dynamicSurfaceNumber >= 0)
{
delete dynamicallyCreatedSurfaces[sds->dynamicSurfaceNumber];
dynamicallyCreatedSurfaces[sds->dynamicSurfaceNumber] = nullptr;
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 (dynamicallyCreatedSurfaces[i] == nullptr)
{
dynamicallyCreatedSurfaces[i] = 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)
quit("!DrawingSurface.DrawImage: cannot draw onto itself");
if ((trans < 0) || (trans > 100))
quit("!DrawingSurface.DrawImage: invalid transparency setting");
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); }
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 simplier blit/draw_sprite could be called (no translucency with alpha channel).
bool needToFreeBitmap = false;
if (dst_width != src->GetWidth() || dst_height != src->GetHeight() ||
src_width != src->GetWidth() || src_height != src->GetHeight())
{
// Resize and/or partial copy specified
Bitmap *newPic = BitmapHelper::CreateBitmap(dst_width, dst_height, src->GetColorDepth());
newPic->StretchBlt(src,
RectWH(src_x, src_y, src_width, src_height),
RectWH(0, 0, dst_width, dst_height));
src = newPic;
needToFreeBitmap = true;
update_polled_stuff_if_runtime();
}
ds = sds->StartDrawing();
sds->PointToGameResolution(&dst_x, &dst_y);
if (src->GetColorDepth() != ds->GetColorDepth()) {
if (sprite_id >= 0)
debug_script_warn("DrawImage: Sprite %d colour depth %d-bit not same as background depth %d-bit", sprite_id, src->GetColorDepth(), ds->GetColorDepth());
else
debug_script_warn("DrawImage: Source image colour depth %d-bit not same as background depth %d-bit", src->GetColorDepth(), ds->GetColorDepth());
}
draw_sprite_support_alpha(ds, sds->hasAlphaChannel != 0, dst_x, dst_y, src, src_has_alpha,
kBlendMode_Alpha, GfxDef::Trans100ToAlpha255(trans));
sds->FinishedDrawing();
if (needToFreeBitmap)
delete src;
}
void DrawingSurface_DrawImageEx(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) || (spriteset[slot] == nullptr))
quit("!DrawingSurface.DrawImage: invalid sprite slot number specified");
DrawingSurface_DrawImageImpl(sds, spriteset[slot], dst_x, dst_y, trans, dst_width, dst_height,
src_x, src_y, src_width, src_height, slot, (game.SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
}
void DrawingSurface_DrawImage(ScriptDrawingSurface* sds, int xx, int yy, int slot, int trans, int width, int height)
{
DrawingSurface_DrawImageEx(sds, xx, yy, slot, trans, width, height, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE);
}
void DrawingSurface_DrawSurfaceEx(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);
}
void DrawingSurface_DrawSurface(ScriptDrawingSurface* target, ScriptDrawingSurface* source, int trans)
{
DrawingSurface_DrawSurfaceEx(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 (game.AllowRelativeRes())
sds->highResCoordinates = (highRes) ? 1 : 0;
}
int DrawingSurface_GetUseHighResCoordinates(ScriptDrawingSurface *sds)
{
return sds->highResCoordinates;
}
int DrawingSurface_GetHeight(ScriptDrawingSurface *sds)
{
Bitmap *ds = sds->GetBitmapSurface();
int height = ds->GetHeight();
sds->SizeToGameResolution(&height);
return height;
}
int DrawingSurface_GetWidth(ScriptDrawingSurface *sds)
{
Bitmap *ds = sds->GetBitmapSurface();
int width = ds->GetWidth();
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) && (play.raw_color > 255)) {
text_color = ds->GetCompatibleColor(1);
debug_script_warn ("RawPrint: Attempted to use hi-color on 256-col background");
}
wouttext_outline(ds, xx, yy, font, text_color, text);
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 = getfontspacing_outlined(font);
sds->PointToGameResolution(&xx, &yy);
sds->SizeToGameResolution(&wid);
if (break_up_text_into_lines(msg, Lines, wid, font) == 0)
return;
Bitmap *ds = sds->StartDrawing();
color_t text_color = sds->currentColour;
for (size_t i = 0; i < Lines.Count(); i++)
{
int drawAtX = xx;
if (alignment & kMAlignHCenter)
{
drawAtX = xx + ((wid / 2) - wgettextwidth(Lines[i], font) / 2);
}
else if (alignment & kMAlignRight)
{
drawAtX = (xx + wid) - wgettextwidth(Lines[i], font);
}
wouttext_outline(ds, drawAtX, yy + linespacing*i, font, text_color, Lines[i]);
}
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();
unsigned int rawPixel = ds->GetPixel(x, y);
unsigned int maskColor = ds->GetMaskColor();
int colDepth = ds->GetColorDepth();
if (rawPixel == maskColor)
{
rawPixel = SCR_COLOR_TRANSPARENT;
}
else if (colDepth > 8)
{
int r = getr_depth(colDepth, rawPixel);
int ds = getg_depth(colDepth, rawPixel);
int b = getb_depth(colDepth, rawPixel);
rawPixel = Game_GetColorFromRGB(r, ds, b);
}
sds->FinishedDrawingReadOnly();
return rawPixel;
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
#include "debug/out.h"
#include "script/script_api.h"
#include "script/script_runtime.h"
// 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_DrawImage_6(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
API_OBJCALL_VOID_PINT6(ScriptDrawingSurface, DrawingSurface_DrawImage);
}
RuntimeScriptValue Sc_DrawingSurface_DrawImage(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
ASSERT_OBJ_PARAM_COUNT(METHOD, 10);
DrawingSurface_DrawImageEx((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_VOID_PINT5_POBJ(ScriptDrawingSurface, DrawingSurface_DrawStringWrapped, const char);
}
// void (ScriptDrawingSurface* target, ScriptDrawingSurface* source, int translev)
RuntimeScriptValue Sc_DrawingSurface_DrawSurface_2(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
API_OBJCALL_VOID_POBJ_PINT(ScriptDrawingSurface, DrawingSurface_DrawSurface, ScriptDrawingSurface);
}
RuntimeScriptValue Sc_DrawingSurface_DrawSurface(void *self, const RuntimeScriptValue *params, int32_t param_count)
{
ASSERT_OBJ_PARAM_COUNT(METHOD, 10);
DrawingSurface_DrawSurfaceEx((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 API for Plugins
//
//=============================================================================
// void (ScriptDrawingSurface *sds, int xx, int yy, int font, const char* texx, ...)
void ScPl_DrawingSurface_DrawString(ScriptDrawingSurface *sds, int xx, int yy, int font, const char* texx, ...)
{
API_PLUGIN_SCRIPT_SPRINTF(texx);
DrawingSurface_DrawString(sds, xx, yy, font, scsf_buffer);
}
void RegisterDrawingSurfaceAPI(ScriptAPIVersion base_api, ScriptAPIVersion compat_api)
{
ccAddExternalObjectFunction("DrawingSurface::Clear^1", Sc_DrawingSurface_Clear);
ccAddExternalObjectFunction("DrawingSurface::CreateCopy^0", Sc_DrawingSurface_CreateCopy);
ccAddExternalObjectFunction("DrawingSurface::DrawCircle^3", Sc_DrawingSurface_DrawCircle);
ccAddExternalObjectFunction("DrawingSurface::DrawImage^6", Sc_DrawingSurface_DrawImage_6);
ccAddExternalObjectFunction("DrawingSurface::DrawImage^10", Sc_DrawingSurface_DrawImage);
ccAddExternalObjectFunction("DrawingSurface::DrawLine^5", Sc_DrawingSurface_DrawLine);
ccAddExternalObjectFunction("DrawingSurface::DrawMessageWrapped^5", Sc_DrawingSurface_DrawMessageWrapped);
ccAddExternalObjectFunction("DrawingSurface::DrawPixel^2", Sc_DrawingSurface_DrawPixel);
ccAddExternalObjectFunction("DrawingSurface::DrawRectangle^4", Sc_DrawingSurface_DrawRectangle);
ccAddExternalObjectFunction("DrawingSurface::DrawString^104", Sc_DrawingSurface_DrawString);
if (base_api < kScriptAPI_v350)
ccAddExternalObjectFunction("DrawingSurface::DrawStringWrapped^6", Sc_DrawingSurface_DrawStringWrapped_Old);
else
ccAddExternalObjectFunction("DrawingSurface::DrawStringWrapped^6", Sc_DrawingSurface_DrawStringWrapped);
ccAddExternalObjectFunction("DrawingSurface::DrawSurface^2", Sc_DrawingSurface_DrawSurface_2);
ccAddExternalObjectFunction("DrawingSurface::DrawSurface^10", Sc_DrawingSurface_DrawSurface);
ccAddExternalObjectFunction("DrawingSurface::DrawTriangle^6", Sc_DrawingSurface_DrawTriangle);
ccAddExternalObjectFunction("DrawingSurface::GetPixel^2", Sc_DrawingSurface_GetPixel);
ccAddExternalObjectFunction("DrawingSurface::Release^0", Sc_DrawingSurface_Release);
ccAddExternalObjectFunction("DrawingSurface::get_DrawingColor", Sc_DrawingSurface_GetDrawingColor);
ccAddExternalObjectFunction("DrawingSurface::set_DrawingColor", Sc_DrawingSurface_SetDrawingColor);
ccAddExternalObjectFunction("DrawingSurface::get_Height", Sc_DrawingSurface_GetHeight);
ccAddExternalObjectFunction("DrawingSurface::get_UseHighResCoordinates", Sc_DrawingSurface_GetUseHighResCoordinates);
ccAddExternalObjectFunction("DrawingSurface::set_UseHighResCoordinates", Sc_DrawingSurface_SetUseHighResCoordinates);
ccAddExternalObjectFunction("DrawingSurface::get_Width", Sc_DrawingSurface_GetWidth);
/* ----------------------- Registering unsafe exports for plugins -----------------------*/
ccAddExternalFunctionForPlugin("DrawingSurface::Clear^1", (void*)DrawingSurface_Clear);
ccAddExternalFunctionForPlugin("DrawingSurface::CreateCopy^0", (void*)DrawingSurface_CreateCopy);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawCircle^3", (void*)DrawingSurface_DrawCircle);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawImage^6", (void*)DrawingSurface_DrawImage);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawLine^5", (void*)DrawingSurface_DrawLine);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawMessageWrapped^5", (void*)DrawingSurface_DrawMessageWrapped);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawPixel^2", (void*)DrawingSurface_DrawPixel);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawRectangle^4", (void*)DrawingSurface_DrawRectangle);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawString^104", (void*)ScPl_DrawingSurface_DrawString);
if (base_api < kScriptAPI_v350)
ccAddExternalFunctionForPlugin("DrawingSurface::DrawStringWrapped^6", (void*)DrawingSurface_DrawStringWrapped_Old);
else
ccAddExternalFunctionForPlugin("DrawingSurface::DrawStringWrapped^6", (void*)DrawingSurface_DrawStringWrapped);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawSurface^2", (void*)DrawingSurface_DrawSurface);
ccAddExternalFunctionForPlugin("DrawingSurface::DrawTriangle^6", (void*)DrawingSurface_DrawTriangle);
ccAddExternalFunctionForPlugin("DrawingSurface::GetPixel^2", (void*)DrawingSurface_GetPixel);
ccAddExternalFunctionForPlugin("DrawingSurface::Release^0", (void*)DrawingSurface_Release);
ccAddExternalFunctionForPlugin("DrawingSurface::get_DrawingColor", (void*)DrawingSurface_GetDrawingColor);
ccAddExternalFunctionForPlugin("DrawingSurface::set_DrawingColor", (void*)DrawingSurface_SetDrawingColor);
ccAddExternalFunctionForPlugin("DrawingSurface::get_Height", (void*)DrawingSurface_GetHeight);
ccAddExternalFunctionForPlugin("DrawingSurface::get_UseHighResCoordinates", (void*)DrawingSurface_GetUseHighResCoordinates);
ccAddExternalFunctionForPlugin("DrawingSurface::set_UseHighResCoordinates", (void*)DrawingSurface_SetUseHighResCoordinates);
ccAddExternalFunctionForPlugin("DrawingSurface::get_Width", (void*)DrawingSurface_GetWidth);
}

View file

@ -0,0 +1,45 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__DRAWINGSURFACE_H
#define __AGS_EE_AC__DRAWINGSURFACE_H
#include "ac/dynobj/scriptdrawingsurface.h"
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 translev);
void DrawingSurface_DrawImage_FullSrc(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_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);
#endif // __AGS_EE_AC__DRAWINGSURFACE_H

View file

@ -0,0 +1,700 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <math.h>
#include "ac/dynamicsprite.h"
#include "ac/common.h"
#include "ac/charactercache.h"
#include "ac/draw.h"
#include "ac/gamesetupstruct.h"
#include "ac/global_dynamicsprite.h"
#include "ac/global_game.h"
#include "ac/math.h" // M_PI
#include "ac/objectcache.h"
#include "ac/path_helper.h"
#include "ac/roomobject.h"
#include "ac/roomstatus.h"
#include "ac/system.h"
#include "debug/debug_log.h"
#include "game/roomstruct.h"
#include "gui/guibutton.h"
#include "ac/spritecache.h"
#include "gfx/graphicsdriver.h"
#include "script/runtimescriptvalue.h"
using namespace Common;
using namespace Engine;
extern GameSetupStruct game;
extern SpriteCache spriteset;
extern RoomStruct thisroom;
extern RoomObject*objs;
extern RoomStatus*croom;
extern CharacterCache *charcache;
extern ObjectCache objcache[MAX_ROOM_OBJECTS];
extern color palette[256];
extern AGS::Engine::IGraphicsDriver *gfxDriver;
char check_dynamic_sprites_at_exit = 1;
// ** 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 ((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(game.SpriteInfos[sds->slot].Width);
}
int DynamicSprite_GetHeight(ScriptDynamicSprite *sds) {
return game_to_data_coord(game.SpriteInfos[sds->slot].Height);
}
int DynamicSprite_GetColorDepth(ScriptDynamicSprite *sds) {
int depth = 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 *newPic = BitmapHelper::CreateBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
newPic->StretchBlt(spriteset[sds->slot],
RectWH(0, 0, game.SpriteInfos[sds->slot].Width, game.SpriteInfos[sds->slot].Height),
RectWH(0, 0, width, height));
delete spriteset[sds->slot];
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, newPic, (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 *newPic = BitmapHelper::CreateTransparentBitmap(game.SpriteInfos[sds->slot].Width, game.SpriteInfos[sds->slot].Height, spriteset[sds->slot]->GetColorDepth());
if (direction == 1)
newPic->FlipBlt(spriteset[sds->slot], 0, 0, Common::kBitmap_HFlip);
else if (direction == 2)
newPic->FlipBlt(spriteset[sds->slot], 0, 0, Common::kBitmap_VFlip);
else if (direction == 3)
newPic->FlipBlt(spriteset[sds->slot], 0, 0, Common::kBitmap_HVFlip);
delete spriteset[sds->slot];
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, newPic, (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 ((game.SpriteInfos[sds->slot].Width != game.SpriteInfos[sourceSprite].Width) ||
(game.SpriteInfos[sds->slot].Height != game.SpriteInfos[sourceSprite].Height))
{
quit("!DynamicSprite.CopyTransparencyMask: sprites are not the same size");
}
Bitmap *target = spriteset[sds->slot];
Bitmap *source = 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 = (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0;
bool src_has_alpha = (game.SpriteInfos[sourceSprite].Flags & SPF_ALPHACHANNEL) != 0;
game.SpriteInfos[sds->slot].Flags &= ~SPF_ALPHACHANNEL;
if (src_has_alpha)
{
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 *newPic = BitmapHelper::CreateTransparentBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
// blit it into the enlarged image
newPic->Blit(spriteset[sds->slot], 0, 0, x, y, game.SpriteInfos[sds->slot].Width, game.SpriteInfos[sds->slot].Height);
delete spriteset[sds->slot];
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, newPic, (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 > game.SpriteInfos[sds->slot].Width) || (height > game.SpriteInfos[sds->slot].Height))
quit("!DynamicSprite.Crop: requested to crop an area larger than the source");
Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
// blit it cropped
newPic->Blit(spriteset[sds->slot], x1, y1, 0, 0, newPic->GetWidth(), newPic->GetHeight());
delete spriteset[sds->slot];
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, newPic, (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)game.SpriteInfos[sds->slot].Width + sinVal * (double)game.SpriteInfos[sds->slot].Height);
height = (sinVal * (double)game.SpriteInfos[sds->slot].Width + cosVal * (double)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 *newPic = BitmapHelper::CreateTransparentBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
// rotate the sprite about its centre
// (+ width%2 fixes one pixel offset problem)
newPic->RotateBlt(spriteset[sds->slot], width / 2 + width % 2, height / 2,
game.SpriteInfos[sds->slot].Width / 2, game.SpriteInfos[sds->slot].Height / 2, itofix(angle));
delete spriteset[sds->slot];
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, newPic, (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 = spriteset[sds->slot];
Bitmap *newPic = BitmapHelper::CreateBitmap(source->GetWidth(), source->GetHeight(), source->GetColorDepth());
tint_image(newPic, source, red, green, blue, saturation, (luminance * 25) / 10);
delete source;
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, newPic, (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('.') == -1)
filename.Append(".bmp");
ResolvedPath rp;
if (!ResolveWritePathAndCreateDirs(filename, rp))
return 0;
return spriteset[sds->slot]->SaveToFile(rp.FullPath, 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()
int gotSlot = spriteset.GetFreeIndex();
if (gotSlot <= 0)
return nullptr;
const Rect &viewport = 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);
Bitmap *newPic = CopyScreenIntoBitmap(width, height);
update_polled_stuff_if_runtime();
// replace the bitmap in the sprite set
add_dynamic_sprite(gotSlot, ReplaceBitmapWithSupportedFormat(newPic));
ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
return new_spr;
}
ScriptDynamicSprite* DynamicSprite_CreateFromExistingSprite(int slot, int preserveAlphaChannel) {
int gotSlot = spriteset.GetFreeIndex();
if (gotSlot <= 0)
return nullptr;
if (!spriteset.DoesSpriteExist(slot))
quitprintf("DynamicSprite.CreateFromExistingSprite: sprite %d does not exist", slot);
// create a new sprite as a copy of the existing one
Bitmap *newPic = BitmapHelper::CreateBitmapCopy(spriteset[slot]);
if (newPic == nullptr)
return nullptr;
bool hasAlpha = (preserveAlphaChannel) && ((game.SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
// replace the bitmap in the sprite set
add_dynamic_sprite(gotSlot, newPic, hasAlpha);
ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
return new_spr;
}
ScriptDynamicSprite* DynamicSprite_CreateFromDrawingSurface(ScriptDrawingSurface *sds, int x, int y, int width, int height)
{
int gotSlot = spriteset.GetFreeIndex();
if (gotSlot <= 0)
return nullptr;
// 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");
int colDepth = ds->GetColorDepth();
Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, colDepth);
if (newPic == nullptr)
return nullptr;
newPic->Blit(ds, x, y, 0, 0, width, height);
sds->FinishedDrawingReadOnly();
add_dynamic_sprite(gotSlot, newPic, (sds->hasAlphaChannel != 0));
ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
return new_spr;
}
ScriptDynamicSprite* DynamicSprite_Create(int width, int height, int alphaChannel)
{
data_to_game_coords(&width, &height);
int gotSlot = spriteset.GetFreeIndex();
if (gotSlot <= 0)
return nullptr;
Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, game.GetColorDepth());
if (newPic == nullptr)
return nullptr;
if ((alphaChannel) && (game.GetColorDepth() < 32))
alphaChannel = false;
add_dynamic_sprite(gotSlot, ReplaceBitmapWithSupportedFormat(newPic), alphaChannel != 0);
ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
return new_spr;
}
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 = play.bg_frame;
}
else if ((frame < 0) || ((size_t)frame >= thisroom.BgFrameCount))
quit("!DynamicSprite.CreateFromBackground: invalid frame specified");
if (x1 == SCR_NO_VALUE) {
x1 = 0;
y1 = 0;
width = play.room_width;
height = play.room_height;
}
else if ((x1 < 0) || (y1 < 0) || (width < 1) || (height < 1) ||
(x1 + width > play.room_width) || (y1 + height > play.room_height))
quit("!DynamicSprite.CreateFromBackground: invalid co-ordinates specified");
data_to_game_coords(&x1, &y1);
data_to_game_coords(&width, &height);
int gotSlot = spriteset.GetFreeIndex();
if (gotSlot <= 0)
return nullptr;
// create a new sprite as a copy of the existing one
Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, thisroom.BgFrames[frame].Graphic->GetColorDepth());
if (newPic == nullptr)
return nullptr;
newPic->Blit(thisroom.BgFrames[frame].Graphic.get(), x1, y1, 0, 0, width, height);
// replace the bitmap in the sprite set
add_dynamic_sprite(gotSlot, newPic);
ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
return new_spr;
}
//=============================================================================
void add_dynamic_sprite(int gotSlot, Bitmap *redin, bool hasAlpha) {
spriteset.SetSprite(gotSlot, redin);
game.SpriteInfos[gotSlot].Flags = SPF_DYNAMICALLOC;
if (redin->GetColorDepth() > 8)
game.SpriteInfos[gotSlot].Flags |= SPF_HICOLOR;
if (redin->GetColorDepth() > 16)
game.SpriteInfos[gotSlot].Flags |= SPF_TRUECOLOR;
if (hasAlpha)
game.SpriteInfos[gotSlot].Flags |= SPF_ALPHACHANNEL;
game.SpriteInfos[gotSlot].Width = redin->GetWidth();
game.SpriteInfos[gotSlot].Height = redin->GetHeight();
}
void free_dynamic_sprite (int gotSlot) {
int tt;
if ((gotSlot < 0) || (gotSlot >= spriteset.GetSpriteSlotCount()))
quit("!FreeDynamicSprite: invalid slot number");
if ((game.SpriteInfos[gotSlot].Flags & SPF_DYNAMICALLOC) == 0)
quitprintf("!DeleteSprite: Attempted to free static sprite %d that was not loaded by the script", gotSlot);
spriteset.RemoveSprite(gotSlot, true);
game.SpriteInfos[gotSlot].Flags = 0;
game.SpriteInfos[gotSlot].Width = 0;
game.SpriteInfos[gotSlot].Height = 0;
// ensure it isn't still on any GUI buttons
for (tt = 0; tt < numguibuts; tt++) {
if (guibuts[tt].IsDeleted())
continue;
if (guibuts[tt].Image == gotSlot)
guibuts[tt].Image = 0;
if (guibuts[tt].CurrentImage == gotSlot)
guibuts[tt].CurrentImage = 0;
if (guibuts[tt].MouseOverImage == gotSlot)
guibuts[tt].MouseOverImage = 0;
if (guibuts[tt].PushedImage == gotSlot)
guibuts[tt].PushedImage = 0;
}
// force refresh of any object caches using the sprite
if (croom != nullptr)
{
for (tt = 0; tt < croom->numobj; tt++)
{
if (objs[tt].num == gotSlot)
{
objs[tt].num = 0;
objcache[tt].sppic = -1;
}
else if (objcache[tt].sppic == gotSlot)
objcache[tt].sppic = -1;
}
}
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
#include "debug/out.h"
#include "script/script_api.h"
#include "script/script_runtime.h"
// 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()
{
ccAddExternalObjectFunction("DynamicSprite::ChangeCanvasSize^4", Sc_DynamicSprite_ChangeCanvasSize);
ccAddExternalObjectFunction("DynamicSprite::CopyTransparencyMask^1", Sc_DynamicSprite_CopyTransparencyMask);
ccAddExternalObjectFunction("DynamicSprite::Crop^4", Sc_DynamicSprite_Crop);
ccAddExternalObjectFunction("DynamicSprite::Delete", Sc_DynamicSprite_Delete);
ccAddExternalObjectFunction("DynamicSprite::Flip^1", Sc_DynamicSprite_Flip);
ccAddExternalObjectFunction("DynamicSprite::GetDrawingSurface^0", Sc_DynamicSprite_GetDrawingSurface);
ccAddExternalObjectFunction("DynamicSprite::Resize^2", Sc_DynamicSprite_Resize);
ccAddExternalObjectFunction("DynamicSprite::Rotate^3", Sc_DynamicSprite_Rotate);
ccAddExternalObjectFunction("DynamicSprite::SaveToFile^1", Sc_DynamicSprite_SaveToFile);
ccAddExternalObjectFunction("DynamicSprite::Tint^5", Sc_DynamicSprite_Tint);
ccAddExternalObjectFunction("DynamicSprite::get_ColorDepth", Sc_DynamicSprite_GetColorDepth);
ccAddExternalObjectFunction("DynamicSprite::get_Graphic", Sc_DynamicSprite_GetGraphic);
ccAddExternalObjectFunction("DynamicSprite::get_Height", Sc_DynamicSprite_GetHeight);
ccAddExternalObjectFunction("DynamicSprite::get_Width", Sc_DynamicSprite_GetWidth);
ccAddExternalStaticFunction("DynamicSprite::Create^3", Sc_DynamicSprite_Create);
ccAddExternalStaticFunction("DynamicSprite::CreateFromBackground", Sc_DynamicSprite_CreateFromBackground);
ccAddExternalStaticFunction("DynamicSprite::CreateFromDrawingSurface^5", Sc_DynamicSprite_CreateFromDrawingSurface);
ccAddExternalStaticFunction("DynamicSprite::CreateFromExistingSprite^1", Sc_DynamicSprite_CreateFromExistingSprite_Old);
ccAddExternalStaticFunction("DynamicSprite::CreateFromExistingSprite^2", Sc_DynamicSprite_CreateFromExistingSprite);
ccAddExternalStaticFunction("DynamicSprite::CreateFromFile", Sc_DynamicSprite_CreateFromFile);
ccAddExternalStaticFunction("DynamicSprite::CreateFromSaveGame", Sc_DynamicSprite_CreateFromSaveGame);
ccAddExternalStaticFunction("DynamicSprite::CreateFromScreenShot", Sc_DynamicSprite_CreateFromScreenShot);
/* ----------------------- Registering unsafe exports for plugins -----------------------*/
ccAddExternalFunctionForPlugin("DynamicSprite::ChangeCanvasSize^4", (void*)DynamicSprite_ChangeCanvasSize);
ccAddExternalFunctionForPlugin("DynamicSprite::CopyTransparencyMask^1", (void*)DynamicSprite_CopyTransparencyMask);
ccAddExternalFunctionForPlugin("DynamicSprite::Crop^4", (void*)DynamicSprite_Crop);
ccAddExternalFunctionForPlugin("DynamicSprite::Delete", (void*)DynamicSprite_Delete);
ccAddExternalFunctionForPlugin("DynamicSprite::Flip^1", (void*)DynamicSprite_Flip);
ccAddExternalFunctionForPlugin("DynamicSprite::GetDrawingSurface^0", (void*)DynamicSprite_GetDrawingSurface);
ccAddExternalFunctionForPlugin("DynamicSprite::Resize^2", (void*)DynamicSprite_Resize);
ccAddExternalFunctionForPlugin("DynamicSprite::Rotate^3", (void*)DynamicSprite_Rotate);
ccAddExternalFunctionForPlugin("DynamicSprite::SaveToFile^1", (void*)DynamicSprite_SaveToFile);
ccAddExternalFunctionForPlugin("DynamicSprite::Tint^5", (void*)DynamicSprite_Tint);
ccAddExternalFunctionForPlugin("DynamicSprite::get_ColorDepth", (void*)DynamicSprite_GetColorDepth);
ccAddExternalFunctionForPlugin("DynamicSprite::get_Graphic", (void*)DynamicSprite_GetGraphic);
ccAddExternalFunctionForPlugin("DynamicSprite::get_Height", (void*)DynamicSprite_GetHeight);
ccAddExternalFunctionForPlugin("DynamicSprite::get_Width", (void*)DynamicSprite_GetWidth);
ccAddExternalFunctionForPlugin("DynamicSprite::Create^3", (void*)DynamicSprite_Create);
ccAddExternalFunctionForPlugin("DynamicSprite::CreateFromBackground", (void*)DynamicSprite_CreateFromBackground);
ccAddExternalFunctionForPlugin("DynamicSprite::CreateFromDrawingSurface^5", (void*)DynamicSprite_CreateFromDrawingSurface);
ccAddExternalFunctionForPlugin("DynamicSprite::CreateFromExistingSprite^1", (void*)DynamicSprite_CreateFromExistingSprite_Old);
ccAddExternalFunctionForPlugin("DynamicSprite::CreateFromExistingSprite^2", (void*)DynamicSprite_CreateFromExistingSprite);
ccAddExternalFunctionForPlugin("DynamicSprite::CreateFromFile", (void*)DynamicSprite_CreateFromFile);
ccAddExternalFunctionForPlugin("DynamicSprite::CreateFromSaveGame", (void*)DynamicSprite_CreateFromSaveGame);
ccAddExternalFunctionForPlugin("DynamicSprite::CreateFromScreenShot", (void*)DynamicSprite_CreateFromScreenShot);
}

View file

@ -0,0 +1,51 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_AC__DYNAMICSPRITE_H
#define __AGS_EE_AC__DYNAMICSPRITE_H
#include "ac/dynobj/scriptdynamicsprite.h"
#include "ac/dynobj/scriptdrawingsurface.h"
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);
void add_dynamic_sprite(int gotSlot, Common::Bitmap *redin, bool hasAlpha = false);
void free_dynamic_sprite (int gotSlot);
#endif // __AGS_EE_AC__DYNAMICSPRITE_H

View file

@ -0,0 +1,35 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__ALLDYNAMICCLASSES_H
#define __AGS_EE_DYNOBJ__ALLDYNAMICCLASSES_H
#include "ac/dynobj/cc_agsdynamicobject.h"
#include "ac/dynobj/cc_audiochannel.h"
#include "ac/dynobj/cc_audioclip.h"
#include "ac/dynobj/cc_character.h"
#include "ac/dynobj/cc_dialog.h"
#include "ac/dynobj/cc_gui.h"
#include "ac/dynobj/cc_guiobject.h"
#include "ac/dynobj/cc_hotspot.h"
#include "ac/dynobj/cc_inventory.h"
#include "ac/dynobj/cc_object.h"
#include "ac/dynobj/cc_region.h"
#include "ac/dynobj/cc_serializer.h"
#endif // __AGS_EE_DYNOBJ__ALLDYNAMICCLASSES_H

View file

@ -0,0 +1,37 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__ALLSCRIPTCLASSES_H
#define __AGS_EE_DYNOBJ__ALLSCRIPTCLASSES_H
#include "ac/dynobj/scriptdatetime.h"
#include "ac/dynobj/scriptdialog.h"
#include "ac/dynobj/scriptdialogoptionsrendering.h"
#include "ac/dynobj/scriptdrawingsurface.h"
#include "ac/dynobj/scriptdynamicsprite.h"
#include "ac/dynobj/scriptgui.h"
#include "ac/dynobj/scripthotspot.h"
#include "ac/dynobj/scriptinvitem.h"
#include "ac/dynobj/scriptmouse.h"
#include "ac/dynobj/scriptobject.h"
#include "ac/dynobj/scriptoverlay.h"
#include "ac/dynobj/scriptregion.h"
#include "ac/dynobj/scriptstring.h"
#include "ac/dynobj/scriptsystem.h"
#include "ac/dynobj/scriptviewframe.h"
#endif // __AGS_EE_DYNOBJ__ALLSCRIPTOBJECTS_H

View file

@ -0,0 +1,130 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <string.h>
#include "core/types.h"
#include "ac/dynobj/cc_agsdynamicobject.h"
#include "ac/common.h" // quit()
#include "util/bbop.h"
using namespace AGS::Common;
// *** The script serialization routines for built-in types
int AGSCCDynamicObject::Dispose(const char *address, bool force) {
// cannot be removed from memory
return 0;
}
void AGSCCDynamicObject::StartSerialize(char *sbuffer) {
bytesSoFar = 0;
serbuffer = sbuffer;
}
void AGSCCDynamicObject::SerializeInt(int val) {
char *chptr = &serbuffer[bytesSoFar];
int *iptr = (int*)chptr;
*iptr = BBOp::Int32FromLE(val);
bytesSoFar += 4;
}
void AGSCCDynamicObject::SerializeFloat(float val) {
char *chptr = &serbuffer[bytesSoFar];
float *fptr = (float*)chptr;
*fptr = BBOp::FloatFromLE(val);
bytesSoFar += 4;
}
int AGSCCDynamicObject::EndSerialize() {
return bytesSoFar;
}
void AGSCCDynamicObject::StartUnserialize(const char *sbuffer, int pTotalBytes) {
bytesSoFar = 0;
totalBytes = pTotalBytes;
serbuffer = (char*)sbuffer;
}
int AGSCCDynamicObject::UnserializeInt() {
if (bytesSoFar >= totalBytes)
quit("Unserialise: internal error: read past EOF");
char *chptr = &serbuffer[bytesSoFar];
bytesSoFar += 4;
return BBOp::Int32FromLE(*((int*)chptr));
}
float AGSCCDynamicObject::UnserializeFloat() {
if (bytesSoFar >= totalBytes)
quit("Unserialise: internal error: read past EOF");
char *chptr = &serbuffer[bytesSoFar];
bytesSoFar += 4;
return BBOp::FloatFromLE(*((float*)chptr));
}
const char* AGSCCDynamicObject::GetFieldPtr(const char *address, intptr_t offset)
{
return address + offset;
}
void AGSCCDynamicObject::Read(const char *address, intptr_t offset, void *dest, int size)
{
memcpy(dest, address + offset, size);
}
uint8_t AGSCCDynamicObject::ReadInt8(const char *address, intptr_t offset)
{
return *(uint8_t*)(address + offset);
}
int16_t AGSCCDynamicObject::ReadInt16(const char *address, intptr_t offset)
{
return *(int16_t*)(address + offset);
}
int32_t AGSCCDynamicObject::ReadInt32(const char *address, intptr_t offset)
{
return *(int32_t*)(address + offset);
}
float AGSCCDynamicObject::ReadFloat(const char *address, intptr_t offset)
{
return *(float*)(address + offset);
}
void AGSCCDynamicObject::Write(const char *address, intptr_t offset, void *src, int size)
{
memcpy((void*)(address + offset), src, size);
}
void AGSCCDynamicObject::WriteInt8(const char *address, intptr_t offset, uint8_t val)
{
*(uint8_t*)(address + offset) = val;
}
void AGSCCDynamicObject::WriteInt16(const char *address, intptr_t offset, int16_t val)
{
*(int16_t*)(address + offset) = val;
}
void AGSCCDynamicObject::WriteInt32(const char *address, intptr_t offset, int32_t val)
{
*(int32_t*)(address + offset) = val;
}
void AGSCCDynamicObject::WriteFloat(const char *address, intptr_t offset, float val)
{
*(float*)(address + offset) = val;
}

View file

@ -0,0 +1,60 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCDYNAMICOBJECT_H
#define __AC_CCDYNAMICOBJECT_H
#include "ac/dynobj/cc_dynamicobject.h"
struct AGSCCDynamicObject : ICCDynamicObject {
protected:
virtual ~AGSCCDynamicObject() = default;
public:
// default implementation
int Dispose(const char *address, bool force) override;
// TODO: pass savegame format version
virtual void Unserialize(int index, const char *serializedData, int dataSize) = 0;
// Legacy support for reading and writing object values by their relative offset
const char* GetFieldPtr(const char *address, intptr_t offset) override;
void Read(const char *address, intptr_t offset, void *dest, int size) override;
uint8_t ReadInt8(const char *address, intptr_t offset) override;
int16_t ReadInt16(const char *address, intptr_t offset) override;
int32_t ReadInt32(const char *address, intptr_t offset) override;
float ReadFloat(const char *address, intptr_t offset) override;
void Write(const char *address, intptr_t offset, void *src, int size) override;
void WriteInt8(const char *address, intptr_t offset, uint8_t val) override;
void WriteInt16(const char *address, intptr_t offset, int16_t val) override;
void WriteInt32(const char *address, intptr_t offset, int32_t val) override;
void WriteFloat(const char *address, intptr_t offset, float val) override;
protected:
// Savegame serialization
// TODO: reimplement with the proper memory stream?!
int bytesSoFar;
int totalBytes;
char *serbuffer;
void StartSerialize(char *sbuffer);
void SerializeInt(int val);
void SerializeFloat(float val);
int EndSerialize();
void StartUnserialize(const char *sbuffer, int pTotalBytes);
int UnserializeInt();
float UnserializeFloat();
};
#endif // __AC_CCDYNAMICOBJECT_H

View file

@ -0,0 +1,36 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_audiochannel.h"
#include "ac/dynobj/scriptaudiochannel.h"
#include "media/audio/audio_system.h"
extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
const char *CCAudioChannel::GetType() {
return "AudioChannel";
}
int CCAudioChannel::Serialize(const char *address, char *buffer, int bufsize) {
ScriptAudioChannel *ach = (ScriptAudioChannel*)address;
StartSerialize(buffer);
SerializeInt(ach->id);
return EndSerialize();
}
void CCAudioChannel::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int id = UnserializeInt();
ccRegisterUnserializedObject(index, &scrAudioChannel[id], this);
}

View file

@ -0,0 +1,29 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__CCAUDIOCHANNEL_H
#define __AGS_EE_DYNOBJ__CCAUDIOCHANNEL_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCAudioChannel final : AGSCCDynamicObject {
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AGS_EE_DYNOBJ__CCAUDIOCHANNEL_H

View file

@ -0,0 +1,36 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_audioclip.h"
#include "ac/dynobj/scriptaudioclip.h"
#include "ac/gamesetupstruct.h"
extern GameSetupStruct game;
const char *CCAudioClip::GetType() {
return "AudioClip";
}
int CCAudioClip::Serialize(const char *address, char *buffer, int bufsize) {
ScriptAudioClip *ach = (ScriptAudioClip*)address;
StartSerialize(buffer);
SerializeInt(ach->id);
return EndSerialize();
}
void CCAudioClip::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int id = UnserializeInt();
ccRegisterUnserializedObject(index, &game.audioClips[id], this);
}

View file

@ -0,0 +1,29 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__CCAUDIOCLIP_H
#define __AGS_EE_DYNOBJ__CCAUDIOCLIP_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCAudioClip final : AGSCCDynamicObject {
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AGS_EE_DYNOBJ__CCAUDIOCLIP_H

View file

@ -0,0 +1,58 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_character.h"
#include "ac/characterinfo.h"
#include "ac/global_character.h"
#include "ac/gamesetupstruct.h"
#include "ac/game_version.h"
extern GameSetupStruct game;
// 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
int CCCharacter::Serialize(const char *address, char *buffer, int bufsize) {
CharacterInfo *chaa = (CharacterInfo*)address;
StartSerialize(buffer);
SerializeInt(chaa->index_id);
return EndSerialize();
}
void CCCharacter::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int num = UnserializeInt();
ccRegisterUnserializedObject(index, &game.chars[num], this);
}
void CCCharacter::WriteInt16(const char *address, intptr_t offset, int16_t val)
{
*(int16_t*)(address + offset) = val;
// 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 reply on the previous behaviour.
if (loaded_game_file_version < kGameVersion_270)
{
const int invoffset = 112;
if (offset >= invoffset && offset < (invoffset + MAX_INV * sizeof(short)))
{
update_invorder();
}
}
}

View file

@ -0,0 +1,34 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCCHARACTER_H
#define __AC_CCCHARACTER_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCCharacter final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
void WriteInt16(const char *address, intptr_t offset, int16_t val) override;
};
#endif // __AC_CCCHARACTER_H

View file

@ -0,0 +1,38 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_dialog.h"
#include "ac/dialog.h"
#include "ac/dialogtopic.h"
#include "ac/gamestructdefines.h"
// return the type name of the object
const char *CCDialog::GetType() {
return "Dialog";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCDialog::Serialize(const char *address, char *buffer, int bufsize) {
ScriptDialog *shh = (ScriptDialog*)address;
StartSerialize(buffer);
SerializeInt(shh->id);
return EndSerialize();
}
void CCDialog::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int num = UnserializeInt();
ccRegisterUnserializedObject(index, &scrDialog[num], this);
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCDIALOG_H
#define __AC_CCDIALOG_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCDialog final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AC_CCDIALOG_H

View file

@ -0,0 +1,161 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <string.h>
#include "cc_dynamicarray.h"
// return the type name of the object
const char *CCDynamicArray::GetType() {
return CC_DYNAMIC_ARRAY_TYPE_NAME;
}
int CCDynamicArray::Dispose(const char *address, bool force) {
address -= 8;
// 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)
{
int *elementCount = (int*)address;
if (elementCount[0] & ARRAY_MANAGED_TYPE_FLAG)
{
elementCount[0] &= ~ARRAY_MANAGED_TYPE_FLAG;
for (int i = 0; i < elementCount[0]; i++)
{
if (elementCount[2 + i] != 0)
{
ccReleaseObjectReference(elementCount[2 + i]);
}
}
}
}
delete address;
return 1;
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCDynamicArray::Serialize(const char *address, char *buffer, int bufsize) {
int *sizeInBytes = &((int*)address)[-1];
int sizeToWrite = *sizeInBytes + 8;
if (sizeToWrite > bufsize)
{
// buffer not big enough, ask for a bigger one
return -sizeToWrite;
}
memcpy(buffer, address - 8, sizeToWrite);
return sizeToWrite;
}
void CCDynamicArray::Unserialize(int index, const char *serializedData, int dataSize) {
char *newArray = new char[dataSize];
memcpy(newArray, serializedData, dataSize);
ccRegisterUnserializedObject(index, &newArray[8], this);
}
DynObjectRef CCDynamicArray::Create(int numElements, int elementSize, bool isManagedType)
{
char *newArray = new char[numElements * elementSize + 8];
memset(newArray, 0, numElements * elementSize + 8);
int *sizePtr = (int*)newArray;
sizePtr[0] = numElements;
sizePtr[1] = numElements * elementSize;
if (isManagedType)
sizePtr[0] |= ARRAY_MANAGED_TYPE_FLAG;
void *obj_ptr = &newArray[8];
int32_t handle = ccRegisterManagedObject(obj_ptr, this);
if (handle == 0)
{
delete[] newArray;
return DynObjectRef(0, nullptr);
}
return DynObjectRef(handle, obj_ptr);
}
const char* CCDynamicArray::GetFieldPtr(const char *address, intptr_t offset)
{
return address + offset;
}
void CCDynamicArray::Read(const char *address, intptr_t offset, void *dest, int size)
{
memcpy(dest, address + offset, size);
}
uint8_t CCDynamicArray::ReadInt8(const char *address, intptr_t offset)
{
return *(uint8_t*)(address + offset);
}
int16_t CCDynamicArray::ReadInt16(const char *address, intptr_t offset)
{
return *(int16_t*)(address + offset);
}
int32_t CCDynamicArray::ReadInt32(const char *address, intptr_t offset)
{
return *(int32_t*)(address + offset);
}
float CCDynamicArray::ReadFloat(const char *address, intptr_t offset)
{
return *(float*)(address + offset);
}
void CCDynamicArray::Write(const char *address, intptr_t offset, void *src, int size)
{
memcpy((void*)(address + offset), src, size);
}
void CCDynamicArray::WriteInt8(const char *address, intptr_t offset, uint8_t val)
{
*(uint8_t*)(address + offset) = val;
}
void CCDynamicArray::WriteInt16(const char *address, intptr_t offset, int16_t val)
{
*(int16_t*)(address + offset) = val;
}
void CCDynamicArray::WriteInt32(const char *address, intptr_t offset, int32_t val)
{
*(int32_t*)(address + offset) = val;
}
void CCDynamicArray::WriteFloat(const char *address, intptr_t offset, float val)
{
*(float*)(address + offset) = val;
}
CCDynamicArray globalDynamicArray;
DynObjectRef DynamicArrayHelpers::CreateStringArray(const std::vector<const char*> items)
{
// NOTE: we need element size of "handle" for array of managed pointers
DynObjectRef arr = globalDynamicArray.Create(items.size(), sizeof(int32_t), true);
if (!arr.second)
return arr;
// Create script strings and put handles into array
int32_t *slots = static_cast<int32_t*>(arr.second);
for (auto s : items)
{
DynObjectRef str = stringClassImpl->CreateString(s);
*(slots++) = str.first;
}
return arr;
}

View file

@ -0,0 +1,58 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __CC_DYNAMICARRAY_H
#define __CC_DYNAMICARRAY_H
#include <vector>
#include "ac/dynobj/cc_dynamicobject.h" // ICCDynamicObject
#define CC_DYNAMIC_ARRAY_TYPE_NAME "CCDynamicArray"
#define ARRAY_MANAGED_TYPE_FLAG 0x80000000
struct CCDynamicArray final : ICCDynamicObject
{
// return the type name of the object
const char *GetType() override;
int Dispose(const char *address, bool force) override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
virtual void Unserialize(int index, const char *serializedData, int dataSize);
// Create managed array object and return a pointer to the beginning of a buffer
DynObjectRef Create(int numElements, int elementSize, bool isManagedType);
// Legacy support for reading and writing object values by their relative offset
const char* GetFieldPtr(const char *address, intptr_t offset) override;
void Read(const char *address, intptr_t offset, void *dest, int size) override;
uint8_t ReadInt8(const char *address, intptr_t offset) override;
int16_t ReadInt16(const char *address, intptr_t offset) override;
int32_t ReadInt32(const char *address, intptr_t offset) override;
float ReadFloat(const char *address, intptr_t offset) override;
void Write(const char *address, intptr_t offset, void *src, int size) override;
void WriteInt8(const char *address, intptr_t offset, uint8_t val) override;
void WriteInt16(const char *address, intptr_t offset, int16_t val) override;
void WriteInt32(const char *address, intptr_t offset, int32_t val) override;
void WriteFloat(const char *address, intptr_t offset, float val) override;
};
extern CCDynamicArray globalDynamicArray;
// Helper functions for setting up dynamic arrays.
namespace DynamicArrayHelpers
{
// Create array of managed strings
DynObjectRef CreateStringArray(const std::vector<const char*>);
};
#endif

View file

@ -0,0 +1,151 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// 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++.
//
//=============================================================================
//#define DEBUG_MANAGED_OBJECTS
#include <stdlib.h>
#include <string.h>
#include "ac/dynobj/cc_dynamicobject.h"
#include "ac/dynobj/managedobjectpool.h"
#include "debug/out.h"
#include "script/cc_error.h"
#include "script/script_common.h"
#include "util/stream.h"
using namespace AGS::Common;
ICCStringClass *stringClassImpl = nullptr;
// set the class that will be used for dynamic strings
void ccSetStringClassImpl(ICCStringClass *theClass) {
stringClassImpl = theClass;
}
// register a memory handle for the object and allow script
// pointers to point to it
int32_t ccRegisterManagedObject(const void *object, ICCDynamicObject *callback, bool plugin_object) {
int32_t handl = pool.AddObject((const char*)object, callback, plugin_object);
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, const void *object, ICCDynamicObject *callback, bool plugin_object) {
return pool.AddUnserializedObject((const char*)object, callback, plugin_object, index);
}
// unregister a particular object
int ccUnRegisterManagedObject(const void *object) {
return pool.RemoveObject((const char*)object);
}
// remove all registered objects
void ccUnregisterAllObjects() {
pool.reset();
}
// serialize all objects to disk
void ccSerializeAllObjects(Stream *out) {
pool.WriteToDisk(out);
}
// un-serialise all objects (will remove all currently registered ones)
int ccUnserializeAllObjects(Stream *in, ICCObjectReader *callback) {
return pool.ReadFromDisk(in, callback);
}
// dispose the object if RefCount==0
void ccAttemptDisposeObject(int32_t handle) {
pool.CheckDispose(handle);
}
// translate between object handles and memory addresses
int32_t ccGetObjectHandleFromAddress(const char *address) {
// set to null
if (address == nullptr)
return 0;
int32_t handl = pool.AddressToHandle(address);
ManagedObjectLog("Line %d WritePtr: %08X to %d", 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;
}
const char *ccGetObjectAddressFromHandle(int32_t handle) {
if (handle == 0) {
return nullptr;
}
const char *addr = pool.HandleToAddress(handle);
ManagedObjectLog("Line %d ReadPtr: %d to %08X", 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, ICCDynamicObject *&manager)
{
if (handle == 0) {
object = nullptr;
manager = nullptr;
return kScValUndefined;
}
ScriptValueType obj_type = 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 pool.AddRef(handle);
}
int ccReleaseObjectReference(int32_t handle) {
if (handle == 0)
return 0;
if (pool.HandleToAddress(handle) == nullptr) {
cc_error("Error releasing pointer: invalid handle %d", handle);
return -1;
}
return pool.SubRef(handle);
}

View file

@ -0,0 +1,116 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// Managed script object interface.
//
//=============================================================================
#ifndef __CC_DYNAMICOBJECT_H
#define __CC_DYNAMICOBJECT_H
#include <utility>
#include "core/types.h"
// Forward declaration
namespace AGS { namespace Common { class Stream; } }
using namespace AGS; // FIXME later
// A pair of managed handle and abstract object pointer
typedef std::pair<int32_t, void*> DynObjectRef;
// OBJECT-BASED SCRIPTING RUNTIME FUNCTIONS
// interface
struct ICCDynamicObject {
// 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(const char *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(const char *address, char *buffer, int bufsize) = 0;
// Legacy support for reading and writing object values by their relative offset.
// WARNING: following were never a part of plugin API, therefore these methods
// should **never** be called for kScValPluginObject script objects!
//
// 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 const char* GetFieldPtr(const char *address, intptr_t offset) = 0;
virtual void Read(const char *address, intptr_t offset, void *dest, int size) = 0;
virtual uint8_t ReadInt8(const char *address, intptr_t offset) = 0;
virtual int16_t ReadInt16(const char *address, intptr_t offset) = 0;
virtual int32_t ReadInt32(const char *address, intptr_t offset) = 0;
virtual float ReadFloat(const char *address, intptr_t offset) = 0;
virtual void Write(const char *address, intptr_t offset, void *src, int size) = 0;
virtual void WriteInt8(const char *address, intptr_t offset, uint8_t val) = 0;
virtual void WriteInt16(const char *address, intptr_t offset, int16_t val) = 0;
virtual void WriteInt32(const char *address, intptr_t offset, int32_t val) = 0;
virtual void WriteFloat(const char *address, intptr_t offset, float val) = 0;
protected:
ICCDynamicObject() = default;
~ICCDynamicObject() = default;
};
struct ICCObjectReader {
// TODO: pass savegame format version
virtual void Unserialize(int index, const char *objectType, const char *serializedData, int dataSize) = 0;
};
struct ICCStringClass {
virtual DynObjectRef CreateString(const char *fromText) = 0;
};
// set the class that will be used for dynamic strings
extern void ccSetStringClassImpl(ICCStringClass *theClass);
// register a memory handle for the object and allow script
// pointers to point to it
extern int32_t ccRegisterManagedObject(const void *object, ICCDynamicObject *, bool plugin_object = false);
// register a de-serialized object
extern int32_t ccRegisterUnserializedObject(int index, const void *object, ICCDynamicObject *, bool plugin_object = false);
// unregister a particular object
extern int ccUnRegisterManagedObject(const void *object);
// remove all registered objects
extern void ccUnregisterAllObjects();
// serialize all objects to disk
extern void ccSerializeAllObjects(Common::Stream *out);
// un-serialise all objects (will remove all currently registered ones)
extern int ccUnserializeAllObjects(Common::Stream *in, ICCObjectReader *callback);
// dispose the object if RefCount==0
extern void ccAttemptDisposeObject(int32_t handle);
// translate between object handles and memory addresses
extern int32_t ccGetObjectHandleFromAddress(const char *address);
// TODO: not sure if it makes any sense whatsoever to use "const char*"
// in these functions, might as well change to char* or just void*.
extern const char *ccGetObjectAddressFromHandle(int32_t handle);
extern int ccAddObjectReference(int32_t handle);
extern int ccReleaseObjectReference(int32_t handle);
extern ICCStringClass *stringClassImpl;
#endif // __CC_DYNAMICOBJECT_H

View file

@ -0,0 +1,11 @@
#ifndef ADDR_AND_MANAGER_H
#define ADDR_AND_MANAGER_H
#include "script/runtimescriptvalue.h"
#include "ac/dynobj/cc_dynamicobject.h"
extern ScriptValueType ccGetObjectAddressAndManagerFromHandle(
int32_t handle, void *&object, ICCDynamicObject *&manager);
#endif

View file

@ -0,0 +1,38 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_gui.h"
#include "ac/dynobj/scriptgui.h"
extern ScriptGUI *scrGui;
// return the type name of the object
const char *CCGUI::GetType() {
return "GUI";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCGUI::Serialize(const char *address, char *buffer, int bufsize) {
ScriptGUI *shh = (ScriptGUI*)address;
StartSerialize(buffer);
SerializeInt(shh->id);
return EndSerialize();
}
void CCGUI::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int num = UnserializeInt();
ccRegisterUnserializedObject(index, &scrGui[num], this);
}

View file

@ -0,0 +1,32 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCGUI_H
#define __AC_CCGUI_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCGUI final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AC_CCGUI_H

View file

@ -0,0 +1,42 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_guiobject.h"
#include "ac/dynobj/scriptgui.h"
#include "gui/guimain.h"
#include "gui/guiobject.h"
using AGS::Common::GUIObject;
// return the type name of the object
const char *CCGUIObject::GetType() {
return "GUIObject";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCGUIObject::Serialize(const char *address, char *buffer, int bufsize) {
GUIObject *guio = (GUIObject*)address;
StartSerialize(buffer);
SerializeInt(guio->ParentId);
SerializeInt(guio->Id);
return EndSerialize();
}
void CCGUIObject::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int guinum = UnserializeInt();
int objnum = UnserializeInt();
ccRegisterUnserializedObject(index, guis[guinum].GetControl(objnum), this);
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCGUIOBJECT_H
#define __AC_CCGUIOBJECT_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCGUIObject final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AC_CCGUIOBJECT_H

View file

@ -0,0 +1,40 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_hotspot.h"
#include "ac/dynobj/scripthotspot.h"
#include "ac/common_defines.h"
#include "game/roomstruct.h"
extern ScriptHotspot scrHotspot[MAX_ROOM_HOTSPOTS];
// return the type name of the object
const char *CCHotspot::GetType() {
return "Hotspot";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCHotspot::Serialize(const char *address, char *buffer, int bufsize) {
ScriptHotspot *shh = (ScriptHotspot*)address;
StartSerialize(buffer);
SerializeInt(shh->id);
return EndSerialize();
}
void CCHotspot::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int num = UnserializeInt();
ccRegisterUnserializedObject(index, &scrHotspot[num], this);
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCHOTSPOT_H
#define __AC_CCHOTSPOT_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCHotspot final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AC_CCHOTSPOT_H

View file

@ -0,0 +1,39 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_inventory.h"
#include "ac/dynobj/scriptinvitem.h"
#include "ac/characterinfo.h"
extern ScriptInvItem scrInv[MAX_INV];
// return the type name of the object
const char *CCInventory::GetType() {
return "Inventory";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCInventory::Serialize(const char *address, char *buffer, int bufsize) {
ScriptInvItem *shh = (ScriptInvItem*)address;
StartSerialize(buffer);
SerializeInt(shh->id);
return EndSerialize();
}
void CCInventory::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int num = UnserializeInt();
ccRegisterUnserializedObject(index, &scrInv[num], this);
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCINVENTORY_H
#define __AC_CCINVENTORY_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCInventory final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AC_CCINVENTORY_H

View file

@ -0,0 +1,40 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_object.h"
#include "ac/dynobj/scriptobject.h"
#include "ac/common_defines.h"
#include "game/roomstruct.h"
extern ScriptObject scrObj[MAX_ROOM_OBJECTS];
// return the type name of the object
const char *CCObject::GetType() {
return "Object";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCObject::Serialize(const char *address, char *buffer, int bufsize) {
ScriptObject *shh = (ScriptObject*)address;
StartSerialize(buffer);
SerializeInt(shh->id);
return EndSerialize();
}
void CCObject::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int num = UnserializeInt();
ccRegisterUnserializedObject(index, &scrObj[num], this);
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCOBJECT_H
#define __AC_CCOBJECT_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCObject final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AC_CCOBJECT_H

View file

@ -0,0 +1,40 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/cc_region.h"
#include "ac/dynobj/scriptregion.h"
#include "ac/common_defines.h"
#include "game/roomstruct.h"
extern ScriptRegion scrRegion[MAX_ROOM_REGIONS];
// return the type name of the object
const char *CCRegion::GetType() {
return "Region";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int CCRegion::Serialize(const char *address, char *buffer, int bufsize) {
ScriptRegion *shh = (ScriptRegion*)address;
StartSerialize(buffer);
SerializeInt(shh->id);
return EndSerialize();
}
void CCRegion::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int num = UnserializeInt();
ccRegisterUnserializedObject(index, &scrRegion[num], this);
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_CCREGION_H
#define __AC_CCREGION_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct CCRegion final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
};
#endif // __AC_CCREGION_H

View file

@ -0,0 +1,144 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <string.h>
#include "ac/dynobj/cc_serializer.h"
#include "ac/dynobj/all_dynamicclasses.h"
#include "ac/dynobj/all_scriptclasses.h"
#include "ac/dynobj/scriptcamera.h"
#include "ac/dynobj/scriptcontainers.h"
#include "ac/dynobj/scriptfile.h"
#include "ac/dynobj/scriptuserobject.h"
#include "ac/dynobj/scriptviewport.h"
#include "ac/game.h"
#include "debug/debug_log.h"
#include "plugin/agsplugin.h"
#include "plugin/pluginobjectreader.h"
extern CCGUIObject ccDynamicGUIObject;
extern CCCharacter ccDynamicCharacter;
extern CCHotspot ccDynamicHotspot;
extern CCRegion ccDynamicRegion;
extern CCInventory ccDynamicInv;
extern CCGUI ccDynamicGUI;
extern CCObject ccDynamicObject;
extern CCDialog ccDynamicDialog;
extern ScriptDrawingSurface* dialogOptionsRenderingSurface;
extern ScriptDialogOptionsRendering ccDialogOptionsRendering;
extern PluginObjectReader pluginReaders[MAX_PLUGIN_OBJECT_READERS];
extern int numPluginReaders;
// *** De-serialization of script objects
void AGSDeSerializer::Unserialize(int index, const char *objectType, const char *serializedData, int dataSize) {
if (strcmp(objectType, "GUIObject") == 0) {
ccDynamicGUIObject.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Character") == 0) {
ccDynamicCharacter.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Hotspot") == 0) {
ccDynamicHotspot.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Region") == 0) {
ccDynamicRegion.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Inventory") == 0) {
ccDynamicInv.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Dialog") == 0) {
ccDynamicDialog.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "GUI") == 0) {
ccDynamicGUI.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Object") == 0) {
ccDynamicObject.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "String") == 0) {
ScriptString *scf = new ScriptString();
scf->Unserialize(index, serializedData, dataSize);
}
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, serializedData, dataSize);
}
else if (strcmp(objectType, "DateTime") == 0) {
ScriptDateTime *scf = new ScriptDateTime();
scf->Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "ViewFrame") == 0) {
ScriptViewFrame *scf = new ScriptViewFrame();
scf->Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "DynamicSprite") == 0) {
ScriptDynamicSprite *scf = new ScriptDynamicSprite();
scf->Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "DrawingSurface") == 0) {
ScriptDrawingSurface *sds = new ScriptDrawingSurface();
sds->Unserialize(index, serializedData, dataSize);
if (sds->isLinkedBitmapOnly)
{
dialogOptionsRenderingSurface = sds;
}
}
else if (strcmp(objectType, "DialogOptionsRendering") == 0)
{
ccDialogOptionsRendering.Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "StringDictionary") == 0)
{
Dict_Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "StringSet") == 0)
{
Set_Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Viewport2") == 0)
{
Viewport_Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "Camera2") == 0)
{
Camera_Unserialize(index, serializedData, dataSize);
}
else if (strcmp(objectType, "UserObject") == 0) {
ScriptUserObject *suo = new ScriptUserObject();
suo->Unserialize(index, serializedData, dataSize);
}
else if (!unserialize_audio_script_object(index, objectType, serializedData, dataSize))
{
// check if the type is read by a plugin
for (int ii = 0; ii < numPluginReaders; ii++) {
if (strcmp(objectType, pluginReaders[ii].type) == 0) {
pluginReaders[ii].reader->Unserialize(index, serializedData, dataSize);
return;
}
}
quitprintf("Unserialise: unknown object type: '%s'", objectType);
}
}
AGSDeSerializer ccUnserializer;

View file

@ -0,0 +1,27 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SERIALIZER_H
#define __AC_SERIALIZER_H
#include "ac/dynobj/cc_dynamicobject.h"
struct AGSDeSerializer : ICCObjectReader {
void Unserialize(int index, const char *objectType, const char *serializedData, int dataSize) override;
};
extern AGSDeSerializer ccUnserializer;
#endif // __AC_SERIALIZER_H

View file

@ -0,0 +1,322 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <vector>
#include <string.h>
#include "ac/dynobj/managedobjectpool.h"
#include "ac/dynobj/cc_dynamicarray.h" // globalDynamicArray, constants
#include "debug/out.h"
#include "util/string_utils.h" // fputstring, etc
#include "script/cc_error.h"
#include "script/script_common.h"
#include "util/stream.h"
using namespace AGS::Common;
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) {
if (!o.isUsed()) { return 1; } // already removed
bool canBeRemovedFromPool = o.callback->Dispose(o.addr, force) != 0;
if (!(canBeRemovedFromPool || force)) { return 0; }
auto handle = o.handle;
available_ids.push(o.handle);
handleByAddress.erase(o.addr);
o = ManagedObject();
ManagedObjectLog("Line %d Disposed managed object handle=%d", currentline, handle);
return 1;
}
int32_t ManagedObjectPool::AddRef(int32_t handle) {
if (handle < 0 || (size_t)handle >= objects.size()) { return 0; }
auto & o = objects[handle];
if (!o.isUsed()) { return 0; }
o.refCount += 1;
ManagedObjectLog("Line %d AddRef: handle=%d new refcount=%d", currentline, o.handle, o.refCount);
return o.refCount;
}
int ManagedObjectPool::CheckDispose(int32_t handle) {
if (handle < 0 || (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 < 0 || (size_t)handle >= objects.size()) { return 0; }
auto & o = objects[handle];
if (!o.isUsed()) { return 0; }
o.refCount--;
auto newRefCount = o.refCount;
auto canBeDisposed = (o.addr != disableDisposeForObject);
if (canBeDisposed) {
CheckDispose(handle);
}
// object could be removed at this point, don't use any values.
ManagedObjectLog("Line %d SubRef: handle=%d new refcount=%d canBeDisposed=%d", currentline, handle, newRefCount, canBeDisposed);
return newRefCount;
}
int32_t ManagedObjectPool::AddressToHandle(const char *addr) {
if (addr == nullptr) { return 0; }
auto it = handleByAddress.find(addr);
if (it == handleByAddress.end()) { return 0; }
return it->second;
}
// this function is called often (whenever a pointer is used)
const char* ManagedObjectPool::HandleToAddress(int32_t handle) {
if (handle < 0 || (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, ICCDynamicObject *&manager) {
if (handle < 0 || (size_t)handle >= objects.size()) { return kScValUndefined; }
auto & o = objects[handle];
if (!o.isUsed()) { return kScValUndefined; }
object = (void *)o.addr; // WARNING: This strips the const from the char* pointer.
manager = o.callback;
return o.obj_type;
}
int ManagedObjectPool::RemoveObject(const char *address) {
if (address == nullptr) { return 0; }
auto it = handleByAddress.find(address);
if (it == handleByAddress.end()) { return 0; }
auto & o = objects[it->second];
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::AddObject(const char *address, ICCDynamicObject *callback, bool plugin_object)
{
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());
}
}
auto & o = objects[handle];
if (o.isUsed()) { cc_error("used: %d", handle); return 0; }
o = ManagedObject(plugin_object ? kScValPluginObject : kScValDynamicObject, handle, address, callback);
handleByAddress.insert({address, o.handle});
objectCreationCounter++;
ManagedObjectLog("Allocated managed object handle=%d, type=%s", handle, callback->GetType());
return o.handle;
}
int ManagedObjectPool::AddUnserializedObject(const char *address, ICCDynamicObject *callback, bool plugin_object, int handle)
{
if (handle < 0) { cc_error("Attempt to assign invalid handle: %d", handle); return 0; }
if ((size_t)handle >= objects.size()) {
objects.resize(handle + 1024, ManagedObject());
}
auto & o = objects[handle];
if (o.isUsed()) { cc_error("bad save. used: %d", o.handle); return 0; }
o = ManagedObject(plugin_object ? kScValPluginObject : kScValDynamicObject, handle, address, callback);
handleByAddress.insert({address, o.handle});
ManagedObjectLog("Allocated unserialized managed object handle=%d, type=%s", o.handle, callback->GetType());
return o.handle;
}
void ManagedObjectPool::WriteToDisk(Stream *out) {
// use this opportunity to clean up any non-referenced pointers
RunGarbageCollection();
std::vector<char> 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((char*)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, ICCObjectReader *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);
if (strcmp(typeNameBuffer, CC_DYNAMIC_ARRAY_TYPE_NAME) == 0) {
globalDynamicArray.Unserialize(i, &serializeBuffer.front(), numBytes);
} else {
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);
if (strcmp(typeNameBuffer, CC_DYNAMIC_ARRAY_TYPE_NAME) == 0) {
globalDynamicArray.Unserialize(handle, &serializeBuffer.front(), numBytes);
} else {
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)
while (!available_ids.empty()) { available_ids.pop(); }
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);
}
while (!available_ids.empty()) { available_ids.pop(); }
nextHandle = 1;
}
ManagedObjectPool::ManagedObjectPool() : objectCreationCounter(0), nextHandle(1), available_ids(), objects(RESERVED_SIZE, ManagedObject()), handleByAddress() {
handleByAddress.reserve(RESERVED_SIZE);
}
ManagedObjectPool pool;

View file

@ -0,0 +1,88 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __CC_MANAGEDOBJECTPOOL_H
#define __CC_MANAGEDOBJECTPOOL_H
#include <vector>
#include <queue>
#include <unordered_map>
#include "script/runtimescriptvalue.h"
#include "ac/dynobj/cc_dynamicobject.h" // ICCDynamicObject
namespace AGS { namespace Common { class Stream; }}
using namespace AGS; // FIXME later
struct ManagedObjectPool final {
private:
// TODO: find out if we can make handle size_t
struct ManagedObject {
ScriptValueType obj_type;
int32_t handle;
// TODO: this makes no sense having this as "const char*",
// void* will be proper (and in all related functions)
const char *addr;
ICCDynamicObject *callback;
int refCount;
bool isUsed() const { return obj_type != kScValUndefined; }
ManagedObject()
: obj_type(kScValUndefined), handle(0), addr(nullptr), callback(nullptr), refCount(0) {}
ManagedObject(ScriptValueType obj_type, int32_t handle, const char *addr, ICCDynamicObject * callback)
: obj_type(obj_type), handle(handle), addr(addr), callback(callback), 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<const char *, int32_t> handleByAddress;
void Init(int32_t theHandle, const char *theAddress, ICCDynamicObject *theCallback, ScriptValueType objType);
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(const char *addr);
const char* HandleToAddress(int32_t handle);
ScriptValueType HandleToAddressAndManager(int32_t handle, void *&object, ICCDynamicObject *&manager);
int RemoveObject(const char *address);
void RunGarbageCollectionIfAppropriate();
int AddObject(const char *address, ICCDynamicObject *callback, bool plugin_object);
int AddUnserializedObject(const char *address, ICCDynamicObject *callback, bool plugin_object, int handle);
void WriteToDisk(Common::Stream *out);
int ReadFromDisk(Common::Stream *in, ICCObjectReader *reader);
void reset();
ManagedObjectPool();
const char* disableDisposeForObject {nullptr};
};
extern ManagedObjectPool pool;
#ifdef DEBUG_MANAGED_OBJECTS
#define ManagedObjectLog(...) Debug::Printf(kDbgGroup_ManObj, kDbgMsg_Debug, __VA_ARGS__)
#else
#define ManagedObjectLog(...)
#endif
#endif // __CC_MANAGEDOBJECTPOOL_H

View file

@ -0,0 +1,27 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTAUDIOCHANNEL_H
#define __AGS_EE_DYNOBJ__SCRIPTAUDIOCHANNEL_H
struct ScriptAudioChannel
{
int id;
int reserved;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTAUDIOCHANNEL_H

View file

@ -0,0 +1,64 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptcamera.h"
#include "ac/gamestate.h"
#include "util/bbop.h"
using namespace AGS::Common;
ScriptCamera::ScriptCamera(int id) : _id(id) {}
const char *ScriptCamera::GetType()
{
return "Camera2";
}
int ScriptCamera::Dispose(const char *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;
}
int ScriptCamera::Serialize(const char *address, char *buffer, int bufsize)
{
StartSerialize(buffer);
SerializeInt(_id);
return EndSerialize();
}
void ScriptCamera::Unserialize(int index, const char *serializedData, int dataSize)
{
StartUnserialize(serializedData, dataSize);
_id = UnserializeInt();
ccRegisterUnserializedObject(index, this, this);
}
ScriptCamera *Camera_Unserialize(int handle, const char *serializedData, int dataSize)
{
// 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 = BBOp::Int32FromLE(*((int*)serializedData));
if (id >= 0)
{
auto scam = play.RegisterRoomCamera(id, handle);
if (scam)
return scam;
}
return new ScriptCamera(-1); // make invalid reference
}

View file

@ -0,0 +1,44 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTCAMERA_H
#define __AC_SCRIPTCAMERA_H
#include "ac/dynobj/cc_agsdynamicobject.h"
// 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(const char *address, bool force) override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
private:
int _id = -1; // index of camera in the game state array
};
// Unserialize camera from the memory stream
ScriptCamera *Camera_Unserialize(int handle, const char *serializedData, int dataSize);
#endif // __AC_SCRIPTCAMERA_H

View file

@ -0,0 +1,29 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTCONTAINERS_H
#define __AC_SCRIPTCONTAINERS_H
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, const char *serializedData, int dataSize);
// Create and register new set
ScriptSetBase *Set_Create(bool sorted, bool case_sensitive);
// Unserialize set from the memory stream
ScriptSetBase *Set_Unserialize(int index, const char *serializedData, int dataSize);
#endif // __AC_SCRIPTCONTAINERS_H

View file

@ -0,0 +1,55 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptdatetime.h"
int ScriptDateTime::Dispose(const char *address, bool force) {
// always dispose a DateTime
delete this;
return 1;
}
const char *ScriptDateTime::GetType() {
return "DateTime";
}
int ScriptDateTime::Serialize(const char *address, char *buffer, int bufsize) {
StartSerialize(buffer);
SerializeInt(year);
SerializeInt(month);
SerializeInt(day);
SerializeInt(hour);
SerializeInt(minute);
SerializeInt(second);
SerializeInt(rawUnixTime);
return EndSerialize();
}
void ScriptDateTime::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
year = UnserializeInt();
month = UnserializeInt();
day = UnserializeInt();
hour = UnserializeInt();
minute = UnserializeInt();
second = UnserializeInt();
rawUnixTime = UnserializeInt();
ccRegisterUnserializedObject(index, this, this);
}
ScriptDateTime::ScriptDateTime() {
year = month = day = 0;
hour = minute = second = 0;
rawUnixTime = 0;
}

View file

@ -0,0 +1,36 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTDATETIME_H
#define __AGS_EE_DYNOBJ__SCRIPTDATETIME_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct ScriptDateTime final : AGSCCDynamicObject {
int year, month, day;
int hour, minute, second;
int rawUnixTime;
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
ScriptDateTime();
};
#endif // __AGS_EE_DYNOBJ__SCRIPTDATETIME_H

View file

@ -0,0 +1,26 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTDIALOG_H
#define __AGS_EE_DYNOBJ__SCRIPTDIALOG_H
struct ScriptDialog {
int id;
int reserved;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTDIALOG_H

View file

@ -0,0 +1,53 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptdialogoptionsrendering.h"
// return the type name of the object
const char *ScriptDialogOptionsRendering::GetType() {
return "DialogOptionsRendering";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int ScriptDialogOptionsRendering::Serialize(const char *address, char *buffer, int bufsize) {
return 0;
}
void ScriptDialogOptionsRendering::Unserialize(int index, const char *serializedData, int dataSize) {
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();
}

View file

@ -0,0 +1,47 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTDIALOGOPTIONSRENDERING_H
#define __AC_SCRIPTDIALOGOPTIONSRENDERING_H
#include "ac/dynobj/scriptdrawingsurface.h"
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;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
void Reset();
ScriptDialogOptionsRendering();
};
#endif // __AC_SCRIPTDIALOGOPTIONSRENDERING_H

View file

@ -0,0 +1,50 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptdict.h"
int ScriptDictBase::Dispose(const char *address, bool force)
{
Clear();
delete this;
return 1;
}
const char *ScriptDictBase::GetType()
{
return "StringDictionary";
}
int ScriptDictBase::Serialize(const char *address, char *buffer, int bufsize)
{
size_t total_sz = CalcSerializeSize() + sizeof(int32_t) * 2;
if (bufsize < 0 || total_sz >(size_t)bufsize)
{
// buffer not big enough, ask for a bigger one
return -((int)total_sz);
}
StartSerialize(buffer);
SerializeInt(IsSorted());
SerializeInt(IsCaseSensitive());
SerializeContainer();
return EndSerialize();
}
void ScriptDictBase::Unserialize(int index, const char *serializedData, int dataSize)
{
// NOTE: we expect sorted/case flags are read by external reader;
// this is awkward, but I did not find better design solution atm
StartUnserialize(serializedData, dataSize);
UnserializeContainer(serializedData);
ccRegisterUnserializedObject(index, this, this);
}

View file

@ -0,0 +1,186 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// 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 perfomance impact that would make.
//
//=============================================================================
#ifndef __AC_SCRIPTDICT_H
#define __AC_SCRIPTDICT_H
#include <map>
#include <unordered_map>
#include <string.h>
#include "ac/dynobj/cc_agsdynamicobject.h"
#include "util/string.h"
#include "util/string_types.h"
using namespace AGS::Common;
class ScriptDictBase : public AGSCCDynamicObject
{
public:
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) 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;
private:
virtual size_t CalcSerializeSize() = 0;
virtual void SerializeContainer() = 0;
virtual void UnserializeContainer(const char *serializedData) = 0;
};
template <typename TDict, bool is_sorted, bool is_casesensitive>
class ScriptDictImpl final : public ScriptDictBase
{
public:
typedef typename TDict::const_iterator ConstIterator;
ScriptDictImpl() = default;
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 { return _dic.count(String::Wrapper(key)) != 0; }
const char *Get(const char *key) override
{
auto it = _dic.find(String::Wrapper(key));
if (it == _dic.end()) return nullptr;
return it->second.GetNullableCStr();
}
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;
size_t key_len = strlen(key);
size_t value_len = value ? strlen(value) : 0;
return TryAddItem(key, key_len, value, value_len);
}
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->first.GetCStr()); // keys cannot be null
}
void GetValues(std::vector<const char*> &buf) const override
{
for (auto it = _dic.begin(); it != _dic.end(); ++it)
buf.push_back(it->second.GetNullableCStr()); // values may be null
}
private:
bool TryAddItem(const char *key, size_t key_len, const char *value, size_t value_len)
{
String elem_key(key, key_len);
String elem_value;
if (value)
elem_value.SetString(value, value_len);
_dic[elem_key] = elem_value;
return true;
}
void DeleteItem(ConstIterator it) { /* do nothing */ }
size_t CalcSerializeSize() override
{
size_t total_sz = sizeof(int32_t);
for (auto it = _dic.begin(); it != _dic.end(); ++it)
{
total_sz += sizeof(int32_t) + it->first.GetLength();
total_sz += sizeof(int32_t) + it->second.GetLength();
}
return total_sz;
}
void SerializeContainer() override
{
SerializeInt((int)_dic.size());
for (auto it = _dic.begin(); it != _dic.end(); ++it)
{
SerializeInt((int)it->first.GetLength());
memcpy(&serbuffer[bytesSoFar], it->first.GetCStr(), it->first.GetLength());
bytesSoFar += it->first.GetLength();
if (it->second.GetNullableCStr()) // values may be null
{
SerializeInt((int)it->second.GetLength());
memcpy(&serbuffer[bytesSoFar], it->second.GetCStr(), it->second.GetLength());
bytesSoFar += it->second.GetLength();
}
else
{
SerializeInt(-1);
}
}
}
void UnserializeContainer(const char *serializedData) override
{
size_t item_count = (size_t)UnserializeInt();
for (size_t i = 0; i < item_count; ++i)
{
size_t key_len = UnserializeInt();
int key_pos = bytesSoFar; bytesSoFar += key_len;
size_t value_len = UnserializeInt();
if (value_len == (size_t)-1)
{
TryAddItem(&serializedData[key_pos], key_len, nullptr, 0);
}
else
{
int value_pos = bytesSoFar; bytesSoFar += value_len;
TryAddItem(&serializedData[key_pos], key_len, &serializedData[value_pos], value_len);
}
}
}
TDict _dic;
};
typedef ScriptDictImpl< std::map<String, String>, true, true > ScriptDict;
typedef ScriptDictImpl< std::map<String, String, StrLessNoCase>, true, false > ScriptDictCI;
typedef ScriptDictImpl< std::unordered_map<String, String>, false, true > ScriptHashDict;
typedef ScriptDictImpl< std::unordered_map<String, String, HashStrNoCase, StrEqNoCase>, false, false > ScriptHashDictCI;
#endif // __AC_SCRIPTDICT_H

View file

@ -0,0 +1,129 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptdrawingsurface.h"
#include "ac/spritecache.h"
#include "ac/runtime_defines.h"
#include "ac/common.h"
#include "ac/drawingsurface.h"
#include "ac/gamestate.h"
#include "ac/gamesetupstruct.h"
#include "game/roomstruct.h"
#include "gfx/bitmap.h"
using namespace AGS::Common;
extern RoomStruct thisroom;
extern SpriteCache spriteset;
extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
extern GameState play;
extern GameSetupStruct game;
Bitmap* ScriptDrawingSurface::GetBitmapSurface()
{
// TODO: consider creating weak_ptr here, and store one in the DrawingSurface!
if (roomBackgroundNumber >= 0)
return thisroom.BgFrames[roomBackgroundNumber].Graphic.get();
else if (dynamicSpriteNumber >= 0)
return spriteset[dynamicSpriteNumber];
else if (dynamicSurfaceNumber >= 0)
return dynamicallyCreatedSurfaces[dynamicSurfaceNumber];
else if (linkedBitmapOnly != nullptr)
return linkedBitmapOnly;
else if (roomMaskType > kRoomAreaNone)
return thisroom.GetMask(roomMaskType);
quit("!DrawingSurface: attempted to use surface after Release was called");
return nullptr;
}
Bitmap *ScriptDrawingSurface::StartDrawing()
{
//abufBackup = abuf;
return this->GetBitmapSurface();
}
void ScriptDrawingSurface::FinishedDrawingReadOnly()
{
//abuf = abufBackup;
}
void ScriptDrawingSurface::FinishedDrawing()
{
FinishedDrawingReadOnly();
modified = 1;
}
int ScriptDrawingSurface::Dispose(const char *address, bool force) {
// dispose the drawing surface
DrawingSurface_Release(this);
delete this;
return 1;
}
const char *ScriptDrawingSurface::GetType() {
return "DrawingSurface";
}
int ScriptDrawingSurface::Serialize(const char *address, char *buffer, int bufsize) {
StartSerialize(buffer);
SerializeInt(roomBackgroundNumber & 0xFFFF | (roomMaskType << 16));
SerializeInt(dynamicSpriteNumber);
SerializeInt(dynamicSurfaceNumber);
SerializeInt(currentColour);
SerializeInt(currentColourScript);
SerializeInt(highResCoordinates);
SerializeInt(modified);
SerializeInt(hasAlphaChannel);
SerializeInt(isLinkedBitmapOnly ? 1 : 0);
return EndSerialize();
}
void ScriptDrawingSurface::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int room_ds = UnserializeInt();
roomBackgroundNumber = static_cast<short>(room_ds & 0xFFFF);
roomMaskType = (RoomAreaMask)(room_ds >> 16);
dynamicSpriteNumber = UnserializeInt();
dynamicSurfaceNumber = UnserializeInt();
currentColour = UnserializeInt();
currentColourScript = UnserializeInt();
highResCoordinates = UnserializeInt();
modified = UnserializeInt();
hasAlphaChannel = UnserializeInt();
isLinkedBitmapOnly = (UnserializeInt() != 0);
ccRegisterUnserializedObject(index, this, this);
}
ScriptDrawingSurface::ScriptDrawingSurface()
{
roomBackgroundNumber = -1;
roomMaskType = kRoomAreaNone;
dynamicSpriteNumber = -1;
dynamicSurfaceNumber = -1;
isLinkedBitmapOnly = false;
linkedBitmapOnly = nullptr;
currentColour = 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 (game.IsLegacyHiRes() && game.IsDataInNativeCoordinates())
{
highResCoordinates = 1;
}
}

View file

@ -0,0 +1,55 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTDRAWINGSURFACE_H
#define __AC_SCRIPTDRAWINGSURFACE_H
#include "ac/dynobj/cc_agsdynamicobject.h"
#include "game/roomstruct.h"
namespace AGS { namespace Common { class Bitmap; }}
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;
Common::Bitmap *linkedBitmapOnly;
int currentColour;
int currentColourScript;
int highResCoordinates;
int modified;
int hasAlphaChannel;
//Common::Bitmap* abufBackup;
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
Common::Bitmap* GetBitmapSurface();
Common::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();
};
#endif // __AC_SCRIPTDRAWINGSURFACE_H

View file

@ -0,0 +1,50 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptdynamicsprite.h"
#include "ac/dynamicsprite.h"
int ScriptDynamicSprite::Dispose(const char *address, bool force) {
// always dispose
if ((slot) && (!force))
free_dynamic_sprite(slot);
delete this;
return 1;
}
const char *ScriptDynamicSprite::GetType() {
return "DynamicSprite";
}
int ScriptDynamicSprite::Serialize(const char *address, char *buffer, int bufsize) {
StartSerialize(buffer);
SerializeInt(slot);
return EndSerialize();
}
void ScriptDynamicSprite::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
slot = UnserializeInt();
ccRegisterUnserializedObject(index, this, this);
}
ScriptDynamicSprite::ScriptDynamicSprite(int theSlot) {
slot = theSlot;
ccRegisterManagedObject(this, this);
}
ScriptDynamicSprite::ScriptDynamicSprite() {
slot = 0;
}

View file

@ -0,0 +1,32 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTDYNAMICSPRITE_H
#define __AC_SCRIPTDYNAMICSPRITE_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct ScriptDynamicSprite final : AGSCCDynamicObject {
int slot;
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
ScriptDynamicSprite(int slot);
ScriptDynamicSprite();
};
#endif // __AC_SCRIPTDYNAMICSPRITE_H

View file

@ -0,0 +1,105 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptfile.h"
#include "ac/global_file.h"
// CHECKME: actually NULLs here will be equal to kFile_Open & kFile_Read
const Common::FileOpenMode sc_File::fopenModes[] =
{Common::kFile_Open/*CHECKME, was undefined*/, Common::kFile_Open, Common::kFile_CreateAlways, Common::kFile_Create};
const Common::FileWorkMode sc_File::fworkModes[] =
{Common::kFile_Read/*CHECKME, was undefined*/, Common::kFile_Read, Common::kFile_Write, Common::kFile_Write};
int sc_File::Dispose(const char *address, bool force) {
Close();
delete this;
return 1;
}
const char *sc_File::GetType() {
return "File";
}
int sc_File::Serialize(const char *address, char *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;
}
const char* sc_File::GetFieldPtr(const char *address, intptr_t offset)
{
return address;
}
void sc_File::Read(const char *address, intptr_t offset, void *dest, int size)
{
}
uint8_t sc_File::ReadInt8(const char *address, intptr_t offset)
{
return 0;
}
int16_t sc_File::ReadInt16(const char *address, intptr_t offset)
{
return 0;
}
int32_t sc_File::ReadInt32(const char *address, intptr_t offset)
{
return 0;
}
float sc_File::ReadFloat(const char *address, intptr_t offset)
{
return 0.0;
}
void sc_File::Write(const char *address, intptr_t offset, void *src, int size)
{
}
void sc_File::WriteInt8(const char *address, intptr_t offset, uint8_t val)
{
}
void sc_File::WriteInt16(const char *address, intptr_t offset, int16_t val)
{
}
void sc_File::WriteInt32(const char *address, intptr_t offset, int32_t val)
{
}
void sc_File::WriteFloat(const char *address, intptr_t offset, float val)
{
}

View file

@ -0,0 +1,61 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTFILE_H
#define __AGS_EE_DYNOBJ__SCRIPTFILE_H
#include "ac/dynobj/cc_dynamicobject.h"
#include "util/file.h"
using namespace AGS; // FIXME later
#define scFileRead 1
#define scFileWrite 2
#define scFileAppend 3
struct sc_File final : ICCDynamicObject {
int32_t handle;
static const Common::FileOpenMode fopenModes[];
static const Common::FileWorkMode fworkModes[];
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
int OpenFile(const char *filename, int mode);
void Close();
sc_File();
// Legacy support for reading and writing object values by their relative offset
const char* GetFieldPtr(const char *address, intptr_t offset) override;
void Read(const char *address, intptr_t offset, void *dest, int size) override;
uint8_t ReadInt8(const char *address, intptr_t offset) override;
int16_t ReadInt16(const char *address, intptr_t offset) override;
int32_t ReadInt32(const char *address, intptr_t offset) override;
float ReadFloat(const char *address, intptr_t offset) override;
void Write(const char *address, intptr_t offset, void *src, int size) override;
void WriteInt8(const char *address, intptr_t offset, uint8_t val) override;
void WriteInt16(const char *address, intptr_t offset, int16_t val) override;
void WriteInt32(const char *address, intptr_t offset, int32_t val) override;
void WriteFloat(const char *address, intptr_t offset, float val) override;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTFILE_H

View file

@ -0,0 +1,27 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTGUI_H
#define __AGS_EE_DYNOBJ__SCRIPTGUI_H
// 64 bit: This struct must be 8 byte long
struct ScriptGUI {
int id;
int __padding;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTGUI_H

View file

@ -0,0 +1,26 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTHOTSPOT_H
#define __AGS_EE_DYNOBJ__SCRIPTHOTSPOT_H
struct ScriptHotspot {
int id;
int reserved;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTHOTSPOT_H

View file

@ -0,0 +1,26 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTINVITEM_H
#define __AGS_EE_DYNOBJ__SCRIPTINVITEM_H
struct ScriptInvItem {
int id;
int reserved;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTINVITEM_H

View file

@ -0,0 +1,26 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTMOUSE_H
#define __AGS_EE_DYNOBJ__SCRIPTMOUSE_H
// The text script's "mouse" struct
struct ScriptMouse {
int x,y;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTMOUSE_H

View file

@ -0,0 +1,30 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTOBJECT_H
#define __AGS_EE_DYNOBJ__SCRIPTOBJECT_H
#include "ac/roomobject.h"
// 64 bit: Struct size must be 8 byte for scripts to work
struct ScriptObject {
int id;
//RoomObject *obj;
int __padding;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTOBJECT_H

View file

@ -0,0 +1,83 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptoverlay.h"
#include "ac/common.h"
#include "ac/overlay.h"
#include "ac/runtime_defines.h"
#include "ac/screenoverlay.h"
int ScriptOverlay::Dispose(const char *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
int overlayIndex = find_overlay_of_type(overlayId);
if (overlayIndex >= 0)
{
screenover[overlayIndex].associatedOverlayHandle = 0;
}
// if this is being removed voluntarily (ie. pointer out of
// scope) then remove the associateed overlay
// Otherwise, it's a Restre Game or something so don't
if ((!force) && (!isBackgroundSpeech) && (Overlay_GetValid(this)))
{
Remove();
}
delete this;
return 1;
}
const char *ScriptOverlay::GetType() {
return "Overlay";
}
int ScriptOverlay::Serialize(const char *address, char *buffer, int bufsize) {
StartSerialize(buffer);
SerializeInt(overlayId);
SerializeInt(borderWidth);
SerializeInt(borderHeight);
SerializeInt(isBackgroundSpeech);
return EndSerialize();
}
void ScriptOverlay::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
overlayId = UnserializeInt();
borderWidth = UnserializeInt();
borderHeight = UnserializeInt();
isBackgroundSpeech = UnserializeInt();
ccRegisterUnserializedObject(index, this, this);
}
void ScriptOverlay::Remove()
{
int overlayIndex = find_overlay_of_type(overlayId);
if (overlayIndex < 0)
{
quit("ScriptOverlay::Remove: overlay is not there!");
}
remove_screen_overlay_index(overlayIndex);
overlayId = -1;
}
ScriptOverlay::ScriptOverlay() {
overlayId = -1;
borderWidth = 0;
borderHeight = 0;
isBackgroundSpeech = 0;
}

View file

@ -0,0 +1,34 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTOVERLAY_H
#define __AC_SCRIPTOVERLAY_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct ScriptOverlay final : AGSCCDynamicObject {
int overlayId;
int borderWidth;
int borderHeight;
int isBackgroundSpeech;
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
void Remove();
ScriptOverlay();
};
#endif // __AC_SCRIPTOVERLAY_H

View file

@ -0,0 +1,26 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTREGION_H
#define __AGS_EE_DYNOBJ__SCRIPTREGION_H
struct ScriptRegion {
int id;
int reserved;
};
#endif // __AGS_EE_DYNOBJ__SCRIPTREGION_H

View file

@ -0,0 +1,50 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptset.h"
int ScriptSetBase::Dispose(const char *address, bool force)
{
Clear();
delete this;
return 1;
}
const char *ScriptSetBase::GetType()
{
return "StringSet";
}
int ScriptSetBase::Serialize(const char *address, char *buffer, int bufsize)
{
size_t total_sz = CalcSerializeSize() + sizeof(int32_t) * 2;
if (bufsize < 0 || total_sz > (size_t)bufsize)
{
// buffer not big enough, ask for a bigger one
return -((int)total_sz);
}
StartSerialize(buffer);
SerializeInt(IsSorted());
SerializeInt(IsCaseSensitive());
SerializeContainer();
return EndSerialize();
}
void ScriptSetBase::Unserialize(int index, const char *serializedData, int dataSize)
{
// NOTE: we expect sorted/case flags are read by external reader;
// this is awkward, but I did not find better design solution atm
StartUnserialize(serializedData, dataSize);
UnserializeContainer(serializedData);
ccRegisterUnserializedObject(index, this, this);
}

View file

@ -0,0 +1,144 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// 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 perfomance impact that would make.
//
//=============================================================================
#ifndef __AC_SCRIPTSET_H
#define __AC_SCRIPTSET_H
#include <set>
#include <unordered_set>
#include <string.h>
#include "ac/dynobj/cc_agsdynamicobject.h"
#include "util/string.h"
#include "util/string_types.h"
using namespace AGS::Common;
class ScriptSetBase : public AGSCCDynamicObject
{
public:
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) 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;
private:
virtual size_t CalcSerializeSize() = 0;
virtual void SerializeContainer() = 0;
virtual void UnserializeContainer(const char *serializedData) = 0;
};
template <typename TSet, bool is_sorted, bool is_casesensitive>
class ScriptSetImpl final : public ScriptSetBase
{
public:
typedef typename TSet::const_iterator ConstIterator;
ScriptSetImpl() = default;
bool IsCaseSensitive() const override { return is_casesensitive; }
bool IsSorted() const override { return is_sorted; }
bool Add(const char *item) override
{
if (!item) return false;
size_t len = strlen(item);
return TryAddItem(item, len);
}
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 char *item, size_t len)
{
return _set.insert(String(item, len)).second;
}
void DeleteItem(ConstIterator it) { /* do nothing */ }
size_t CalcSerializeSize() override
{
size_t total_sz = sizeof(int32_t);
for (auto it = _set.begin(); it != _set.end(); ++it)
total_sz += sizeof(int32_t) + it->GetLength();
return total_sz;
}
void SerializeContainer() override
{
SerializeInt((int)_set.size());
for (auto it = _set.begin(); it != _set.end(); ++it)
{
SerializeInt((int)it->GetLength());
memcpy(&serbuffer[bytesSoFar], it->GetCStr(), it->GetLength());
bytesSoFar += it->GetLength();
}
}
void UnserializeContainer(const char *serializedData) override
{
size_t item_count = (size_t)UnserializeInt();
for (size_t i = 0; i < item_count; ++i)
{
size_t len = UnserializeInt();
TryAddItem(&serializedData[bytesSoFar], len);
bytesSoFar += len;
}
}
TSet _set;
};
typedef ScriptSetImpl< std::set<String>, true, true > ScriptSet;
typedef ScriptSetImpl< std::set<String, StrLessNoCase>, true, false > ScriptSetCI;
typedef ScriptSetImpl< std::unordered_set<String>, false, true > ScriptHashSet;
typedef ScriptSetImpl< std::unordered_set<String, HashStrNoCase, StrEqNoCase>, false, false > ScriptHashSetCI;
#endif // __AC_SCRIPTSET_H

View file

@ -0,0 +1,66 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptstring.h"
#include "ac/string.h"
#include <stdlib.h>
#include <string.h>
DynObjectRef ScriptString::CreateString(const char *fromText) {
return CreateNewScriptStringObj(fromText);
}
int ScriptString::Dispose(const char *address, bool force) {
// always dispose
if (text) {
free(text);
text = nullptr;
}
delete this;
return 1;
}
const char *ScriptString::GetType() {
return "String";
}
int ScriptString::Serialize(const char *address, char *buffer, int bufsize) {
StartSerialize(buffer);
auto toSerialize = text ? text : "";
auto len = strlen(toSerialize);
SerializeInt(len);
strcpy(&serbuffer[bytesSoFar], toSerialize);
bytesSoFar += len + 1;
return EndSerialize();
}
void ScriptString::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
int textsize = UnserializeInt();
text = (char*)malloc(textsize + 1);
strcpy(text, &serializedData[bytesSoFar]);
ccRegisterUnserializedObject(index, text, this);
}
ScriptString::ScriptString() {
text = nullptr;
}
ScriptString::ScriptString(const char *fromText) {
text = (char*)malloc(strlen(fromText) + 1);
strcpy(text, fromText);
}

View file

@ -0,0 +1,34 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTSTRING_H
#define __AC_SCRIPTSTRING_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct ScriptString final : AGSCCDynamicObject, ICCStringClass {
char *text;
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
DynObjectRef CreateString(const char *fromText) override;
ScriptString();
ScriptString(const char *fromText);
};
#endif // __AC_SCRIPTSTRING_H

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
//
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTSYSTEM_H
#define __AGS_EE_DYNOBJ__SCRIPTSYSTEM_H
// The text script's "system" struct
struct ScriptSystem {
int width,height;
int coldepth;
int os;
int windowed;
int vsync;
int viewport_width, viewport_height;
char aci_version[10]; // FIXME this when possible, version format is different now
int reserved[5]; // so that future scripts don't overwrite data
};
#endif // __AGS_EE_DYNOBJ__SCRIPTSYSTEM_H

View file

@ -0,0 +1,144 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include <memory.h>
#include "scriptuserobject.h"
// return the type name of the object
const char *ScriptUserObject::GetType()
{
return "UserObject";
}
ScriptUserObject::ScriptUserObject()
: _size(0)
, _data(nullptr)
{
}
ScriptUserObject::~ScriptUserObject()
{
delete [] _data;
}
/* static */ ScriptUserObject *ScriptUserObject::CreateManaged(size_t size)
{
ScriptUserObject *suo = new ScriptUserObject();
suo->Create(nullptr, size);
ccRegisterManagedObject(suo, suo);
return suo;
}
void ScriptUserObject::Create(const char *data, size_t size)
{
delete [] _data;
_data = nullptr;
_size = size;
if (_size > 0)
{
_data = new char[size];
if (data)
memcpy(_data, data, _size);
else
memset(_data, 0, _size);
}
}
int ScriptUserObject::Dispose(const char *address, bool force)
{
delete this;
return 1;
}
int ScriptUserObject::Serialize(const char *address, char *buffer, int bufsize)
{
if (_size > bufsize)
// buffer not big enough, ask for a bigger one
return -_size;
memcpy(buffer, _data, _size);
return _size;
}
void ScriptUserObject::Unserialize(int index, const char *serializedData, int dataSize)
{
Create(serializedData, dataSize);
ccRegisterUnserializedObject(index, this, this);
}
const char* ScriptUserObject::GetFieldPtr(const char *address, intptr_t offset)
{
return _data + offset;
}
void ScriptUserObject::Read(const char *address, intptr_t offset, void *dest, int size)
{
memcpy(dest, _data + offset, size);
}
uint8_t ScriptUserObject::ReadInt8(const char *address, intptr_t offset)
{
return *(uint8_t*)(_data + offset);
}
int16_t ScriptUserObject::ReadInt16(const char *address, intptr_t offset)
{
return *(int16_t*)(_data + offset);
}
int32_t ScriptUserObject::ReadInt32(const char *address, intptr_t offset)
{
return *(int32_t*)(_data + offset);
}
float ScriptUserObject::ReadFloat(const char *address, intptr_t offset)
{
return *(float*)(_data + offset);
}
void ScriptUserObject::Write(const char *address, intptr_t offset, void *src, int size)
{
memcpy((void*)(_data + offset), src, size);
}
void ScriptUserObject::WriteInt8(const char *address, intptr_t offset, uint8_t val)
{
*(uint8_t*)(_data + offset) = val;
}
void ScriptUserObject::WriteInt16(const char *address, intptr_t offset, int16_t val)
{
*(int16_t*)(_data + offset) = val;
}
void ScriptUserObject::WriteInt32(const char *address, intptr_t offset, int32_t val)
{
*(int32_t*)(_data + offset) = val;
}
void ScriptUserObject::WriteFloat(const char *address, intptr_t offset, float val)
{
*(float*)(_data + offset) = val;
}
// Allocates managed struct containing two ints: X and Y
ScriptUserObject *ScriptStructHelpers::CreatePoint(int x, int y)
{
ScriptUserObject *suo = ScriptUserObject::CreateManaged(sizeof(int32_t) * 2);
suo->WriteInt32((const char*)suo, 0, x);
suo->WriteInt32((const char*)suo, sizeof(int32_t), y);
return suo;
}

View file

@ -0,0 +1,75 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// Managed object, which size and contents are defined by user script
//
//=============================================================================
#ifndef __AGS_EE_DYNOBJ__SCRIPTUSERSTRUCT_H
#define __AGS_EE_DYNOBJ__SCRIPTUSERSTRUCT_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct ScriptUserObject final : ICCDynamicObject
{
public:
ScriptUserObject();
protected:
virtual ~ScriptUserObject();
public:
static ScriptUserObject *CreateManaged(size_t size);
void Create(const char *data, size_t size);
// return the type name of the object
const char *GetType() override;
int Dispose(const char *address, bool force) override;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(const char *address, char *buffer, int bufsize) override;
virtual void Unserialize(int index, const char *serializedData, int dataSize);
// Support for reading and writing object values by their relative offset
const char* GetFieldPtr(const char *address, intptr_t offset) override;
void Read(const char *address, intptr_t offset, void *dest, int size) override;
uint8_t ReadInt8(const char *address, intptr_t offset) override;
int16_t ReadInt16(const char *address, intptr_t offset) override;
int32_t ReadInt32(const char *address, intptr_t offset) override;
float ReadFloat(const char *address, intptr_t offset) override;
void Write(const char *address, intptr_t offset, void *src, int size) override;
void WriteInt8(const char *address, intptr_t offset, uint8_t val) override;
void WriteInt16(const char *address, intptr_t offset, int16_t val) override;
void WriteInt32(const char *address, intptr_t offset, int32_t val) override;
void WriteFloat(const char *address, intptr_t offset, float val) override;
private:
// NOTE: we use signed int for Size at the moment, because the managed
// object interface's Serialize() function requires the object to return
// negative value of size in case the provided buffer was not large
// enough. Since this interface is also a part of Plugin API, we would
// need more significant change to program before we could use different
// approach.
int32_t _size;
char *_data;
};
// Helper functions for setting up custom managed structs based on ScriptUserObject.
namespace ScriptStructHelpers
{
// Creates a managed Point object, represented as a pair of X and Y coordinates.
ScriptUserObject *CreatePoint(int x, int y);
};
#endif // __AGS_EE_DYNOBJ__SCRIPTUSERSTRUCT_H

View file

@ -0,0 +1,53 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptviewframe.h"
int ScriptViewFrame::Dispose(const char *address, bool force) {
// always dispose a ViewFrame
delete this;
return 1;
}
const char *ScriptViewFrame::GetType() {
return "ViewFrame";
}
int ScriptViewFrame::Serialize(const char *address, char *buffer, int bufsize) {
StartSerialize(buffer);
SerializeInt(view);
SerializeInt(loop);
SerializeInt(frame);
return EndSerialize();
}
void ScriptViewFrame::Unserialize(int index, const char *serializedData, int dataSize) {
StartUnserialize(serializedData, dataSize);
view = UnserializeInt();
loop = UnserializeInt();
frame = UnserializeInt();
ccRegisterUnserializedObject(index, this, this);
}
ScriptViewFrame::ScriptViewFrame(int p_view, int p_loop, int p_frame) {
view = p_view;
loop = p_loop;
frame = p_frame;
}
ScriptViewFrame::ScriptViewFrame() {
view = -1;
loop = -1;
frame = -1;
}

View file

@ -0,0 +1,32 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTVIEWFRAME_H
#define __AC_SCRIPTVIEWFRAME_H
#include "ac/dynobj/cc_agsdynamicobject.h"
struct ScriptViewFrame final : AGSCCDynamicObject {
int view, loop, frame;
int Dispose(const char *address, bool force) override;
const char *GetType() override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
ScriptViewFrame(int p_view, int p_loop, int p_frame);
ScriptViewFrame();
};
#endif // __AC_SCRIPTVIEWFRAME_H

View file

@ -0,0 +1,64 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#include "ac/dynobj/scriptviewport.h"
#include "ac/gamestate.h"
#include "util/bbop.h"
using namespace AGS::Common;
ScriptViewport::ScriptViewport(int id) : _id(id) {}
const char *ScriptViewport::GetType()
{
return "Viewport2";
}
int ScriptViewport::Dispose(const char *address, bool force)
{
// Note that ScriptViewport is a reference to actual Viewport object,
// and this deletes the reference, while viewport may remain in GameState.
delete this;
return 1;
}
int ScriptViewport::Serialize(const char *address, char *buffer, int bufsize)
{
StartSerialize(buffer);
SerializeInt(_id);
return EndSerialize();
}
void ScriptViewport::Unserialize(int index, const char *serializedData, int dataSize)
{
StartUnserialize(serializedData, dataSize);
_id = UnserializeInt();
ccRegisterUnserializedObject(index, this, this);
}
ScriptViewport *Viewport_Unserialize(int handle, const char *serializedData, int dataSize)
{
// 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 Viewport gets removed.
const int id = BBOp::Int32FromLE(*((int*)serializedData));
if (id >= 0)
{
auto scview = play.RegisterRoomViewport(id, handle);
if (scview)
return scview;
}
return new ScriptViewport(-1); // make invalid reference
}

View file

@ -0,0 +1,43 @@
//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
#ifndef __AC_SCRIPTVIEWPORT_H
#define __AC_SCRIPTVIEWPORT_H
#include "ac/dynobj/cc_agsdynamicobject.h"
// ScriptViewport keeps a reference to actual room Viewport in script.
struct ScriptViewport final : AGSCCDynamicObject
{
public:
ScriptViewport(int id);
// Get viewport index; negative means the viewport was deleted
int GetID() const { return _id; }
void SetID(int id) { _id = id; }
// Reset viewport index to indicate that this reference is no longer valid
void Invalidate() { _id = -1; }
const char *GetType() override;
int Dispose(const char *address, bool force) override;
int Serialize(const char *address, char *buffer, int bufsize) override;
void Unserialize(int index, const char *serializedData, int dataSize) override;
private:
int _id = -1; // index of viewport in the game state array
};
// Unserialize viewport from the memory stream
ScriptViewport *Viewport_Unserialize(int handle, const char *serializedData, int dataSize);
#endif // __AC_SCRIPTVIEWPORT_H

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