aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/wintermute/AdActor.cpp1339
-rw-r--r--engines/wintermute/AdActor.h107
-rw-r--r--engines/wintermute/AdActorDir.cpp52
-rw-r--r--engines/wintermute/AdActorDir.h46
-rw-r--r--engines/wintermute/AdEntity.cpp959
-rw-r--r--engines/wintermute/AdGame.cpp2062
-rw-r--r--engines/wintermute/AdGame.h162
-rw-r--r--engines/wintermute/AdInventory.cpp119
-rw-r--r--engines/wintermute/AdInventory.h52
-rw-r--r--engines/wintermute/AdInventoryBox.cpp368
-rw-r--r--engines/wintermute/AdInventoryBox.h63
-rw-r--r--engines/wintermute/AdItem.cpp754
-rw-r--r--engines/wintermute/AdItem.h70
-rw-r--r--engines/wintermute/AdLayer.cpp535
-rw-r--r--engines/wintermute/AdLayer.h58
-rw-r--r--engines/wintermute/AdNodeState.cpp169
-rw-r--r--engines/wintermute/AdNodeState.h58
-rw-r--r--engines/wintermute/AdObject.cpp1190
-rw-r--r--engines/wintermute/AdPath.cpp112
-rw-r--r--engines/wintermute/AdPath.h56
-rw-r--r--engines/wintermute/AdPathPoint.cpp75
-rw-r--r--engines/wintermute/AdPathPoint.h50
-rw-r--r--engines/wintermute/AdRegion.cpp394
-rw-r--r--engines/wintermute/AdRegion.h58
-rw-r--r--engines/wintermute/AdResponse.cpp143
-rw-r--r--engines/wintermute/AdResponse.h61
-rw-r--r--engines/wintermute/AdResponseBox.cpp631
-rw-r--r--engines/wintermute/AdResponseBox.h85
-rw-r--r--engines/wintermute/AdResponseContext.cpp70
-rw-r--r--engines/wintermute/AdResponseContext.h50
-rw-r--r--engines/wintermute/AdRotLevel.cpp159
-rw-r--r--engines/wintermute/AdRotLevel.h49
-rw-r--r--engines/wintermute/AdScaleLevel.cpp157
-rw-r--r--engines/wintermute/AdScaleLevel.h50
-rw-r--r--engines/wintermute/AdScene.cpp2760
-rw-r--r--engines/wintermute/AdScene.h181
-rw-r--r--engines/wintermute/AdSceneNode.cpp83
-rw-r--r--engines/wintermute/AdSceneNode.h54
-rw-r--r--engines/wintermute/AdSceneState.cpp87
-rw-r--r--engines/wintermute/AdSceneState.h51
-rw-r--r--engines/wintermute/AdSentence.cpp317
-rw-r--r--engines/wintermute/AdSentence.h83
-rw-r--r--engines/wintermute/AdSpriteSet.cpp312
-rw-r--r--engines/wintermute/AdSpriteSet.h54
-rw-r--r--engines/wintermute/AdTalkDef.cpp260
-rw-r--r--engines/wintermute/AdTalkDef.h58
-rw-r--r--engines/wintermute/AdTalkHolder.cpp355
-rw-r--r--engines/wintermute/AdTalkNode.cpp263
-rw-r--r--engines/wintermute/AdTalkNode.h63
-rw-r--r--engines/wintermute/AdWaypointGroup.cpp260
-rw-r--r--engines/wintermute/AdWaypointGroup.h58
51 files changed, 15662 insertions, 0 deletions
diff --git a/engines/wintermute/AdActor.cpp b/engines/wintermute/AdActor.cpp
new file mode 100644
index 0000000000..a5d269e13a
--- /dev/null
+++ b/engines/wintermute/AdActor.cpp
@@ -0,0 +1,1339 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "dctypes.h"
+#include "persistent.h"
+#include "BObject.h"
+#include "AdActor.h"
+#include "AdGame.h"
+#include "BParser.h"
+#include "ScValue.h"
+#include "ScStack.h"
+#include "BObject.h"
+#include "BSound.h"
+#include "AdScene.h"
+#include "AdEntity.h"
+#include "AdSpriteSet.h"
+#include "AdWaypointGroup.h"
+#include "AdPath.h"
+#include "AdSentence.h"
+#include "AdPath.h"
+#include "ScScript.h"
+#include "BRegion.h"
+#include "BFileManager.h"
+#include "AdPath.h"
+#include "utils.h"
+#include "PlatformSDL.h"
+#include <math.h>
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdActor, false)
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdActor::CAdActor(CBGame *inGame): CAdTalkHolder(inGame) {
+ m_Path = new CAdPath(Game);
+
+ m_Type = OBJECT_ACTOR;
+ m_Dir = DI_LEFT;
+
+ m_WalkSprite = NULL;
+ m_StandSprite = NULL;
+ m_TurnLeftSprite = NULL;
+ m_TurnRightSprite = NULL;
+
+ m_TargetPoint = new CBPoint;
+ m_AfterWalkDir = DI_NONE;
+
+ m_AnimSprite2 = NULL;
+
+ SetDefaultAnimNames();
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::SetDefaultAnimNames() {
+ m_TalkAnimName = NULL;
+ CBUtils::SetString(&m_TalkAnimName, "talk");
+
+ m_IdleAnimName = NULL;
+ CBUtils::SetString(&m_IdleAnimName, "idle");
+
+ m_WalkAnimName = NULL;
+ CBUtils::SetString(&m_WalkAnimName, "walk");
+
+ m_TurnLeftAnimName = NULL;
+ CBUtils::SetString(&m_TurnLeftAnimName, "turnleft");
+
+ m_TurnRightAnimName = NULL;
+ CBUtils::SetString(&m_TurnRightAnimName, "turnright");
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CAdActor::~CAdActor() {
+ delete m_Path;
+ delete m_TargetPoint;
+ m_Path = NULL;
+ m_TargetPoint = NULL;
+
+ delete m_WalkSprite;
+ delete m_StandSprite;
+ delete m_TurnLeftSprite;
+ delete m_TurnRightSprite;
+ m_WalkSprite = NULL;
+ m_StandSprite = NULL;
+ m_TurnLeftSprite = NULL;
+ m_TurnRightSprite = NULL;
+
+ m_AnimSprite2 = NULL; // ref only
+
+ for (int i = 0; i < m_TalkSprites.GetSize(); i++) {
+ delete m_TalkSprites[i];
+ }
+ m_TalkSprites.RemoveAll();
+
+ for (int i = 0; i < m_TalkSpritesEx.GetSize(); i++) {
+ delete m_TalkSpritesEx[i];
+ }
+ m_TalkSpritesEx.RemoveAll();
+
+
+ delete[] m_TalkAnimName;
+ delete[] m_IdleAnimName;
+ delete[] m_WalkAnimName;
+ delete[] m_TurnLeftAnimName;
+ delete[] m_TurnRightAnimName;
+ m_TalkAnimName = NULL;
+ m_IdleAnimName = NULL;
+ m_WalkAnimName = NULL;
+ m_TurnLeftAnimName = NULL;
+ m_TurnRightAnimName = NULL;
+
+ for (int i = 0; i < m_Anims.GetSize(); i++) {
+ delete m_Anims[i];
+ m_Anims[i] = NULL;
+ }
+ m_Anims.RemoveAll();
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdActor::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing ACTOR file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(ACTOR)
+TOKEN_DEF(X)
+TOKEN_DEF(Y)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(NAME)
+TOKEN_DEF(SCALABLE)
+TOKEN_DEF(REGISTRABLE)
+TOKEN_DEF(INTERACTIVE)
+TOKEN_DEF(SHADOWABLE)
+TOKEN_DEF(COLORABLE)
+TOKEN_DEF(ACTIVE)
+TOKEN_DEF(WALK)
+TOKEN_DEF(STAND)
+TOKEN_DEF(TALK_SPECIAL)
+TOKEN_DEF(TALK)
+TOKEN_DEF(TURN_LEFT)
+TOKEN_DEF(TURN_RIGHT)
+TOKEN_DEF(EVENTS)
+TOKEN_DEF(FONT)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(SOUND_VOLUME)
+TOKEN_DEF(SOUND_PANNING)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PROPERTY)
+TOKEN_DEF(BLOCKED_REGION)
+TOKEN_DEF(WAYPOINTS)
+TOKEN_DEF(IGNORE_ITEMS)
+TOKEN_DEF(ROTABLE)
+TOKEN_DEF(ROTATABLE)
+TOKEN_DEF(ALPHA_COLOR)
+TOKEN_DEF(SCALE)
+TOKEN_DEF(RELATIVE_SCALE)
+TOKEN_DEF(ALPHA)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF(ANIMATION)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ACTOR)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(SCALABLE)
+ TOKEN_TABLE(REGISTRABLE)
+ TOKEN_TABLE(INTERACTIVE)
+ TOKEN_TABLE(SHADOWABLE)
+ TOKEN_TABLE(COLORABLE)
+ TOKEN_TABLE(ACTIVE)
+ TOKEN_TABLE(WALK)
+ TOKEN_TABLE(STAND)
+ TOKEN_TABLE(TALK_SPECIAL)
+ TOKEN_TABLE(TALK)
+ TOKEN_TABLE(TURN_LEFT)
+ TOKEN_TABLE(TURN_RIGHT)
+ TOKEN_TABLE(EVENTS)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(SOUND_VOLUME)
+ TOKEN_TABLE(SOUND_PANNING)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PROPERTY)
+ TOKEN_TABLE(BLOCKED_REGION)
+ TOKEN_TABLE(WAYPOINTS)
+ TOKEN_TABLE(IGNORE_ITEMS)
+ TOKEN_TABLE(ROTABLE)
+ TOKEN_TABLE(ROTATABLE)
+ TOKEN_TABLE(ALPHA_COLOR)
+ TOKEN_TABLE(SCALE)
+ TOKEN_TABLE(RELATIVE_SCALE)
+ TOKEN_TABLE(ALPHA)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE(ANIMATION)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_ACTOR) {
+ Game->LOG(0, "'ACTOR' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ CAdGame *AdGame = (CAdGame *)Game;
+ CAdSpriteSet *spr = NULL;
+ int ar = 0, ag = 0, ab = 0, alpha = 0;
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_X:
+ parser.ScanStr((char *)params, "%d", &m_PosX);
+ break;
+
+ case TOKEN_Y:
+ parser.ScanStr((char *)params, "%d", &m_PosY);
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ SetCaption((char *)params);
+ break;
+
+ case TOKEN_FONT:
+ SetFont((char *)params);
+ break;
+
+ case TOKEN_SCALABLE:
+ parser.ScanStr((char *)params, "%b", &m_Zoomable);
+ break;
+
+ case TOKEN_ROTABLE:
+ case TOKEN_ROTATABLE:
+ parser.ScanStr((char *)params, "%b", &m_Rotatable);
+ break;
+
+ case TOKEN_REGISTRABLE:
+ case TOKEN_INTERACTIVE:
+ parser.ScanStr((char *)params, "%b", &m_Registrable);
+ break;
+
+ case TOKEN_SHADOWABLE:
+ case TOKEN_COLORABLE:
+ parser.ScanStr((char *)params, "%b", &m_Shadowable);
+ break;
+
+ case TOKEN_ACTIVE:
+ parser.ScanStr((char *)params, "%b", &m_Active);
+ break;
+
+ case TOKEN_WALK:
+ delete m_WalkSprite;
+ m_WalkSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->m_TexWalkLifeTime, CACHE_HALF))) cmd = PARSERR_GENERIC;
+ else m_WalkSprite = spr;
+ break;
+
+ case TOKEN_TALK:
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->m_TexTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else m_TalkSprites.Add(spr);
+ break;
+
+ case TOKEN_TALK_SPECIAL:
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->m_TexTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else m_TalkSpritesEx.Add(spr);
+ break;
+
+ case TOKEN_STAND:
+ delete m_StandSprite;
+ m_StandSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->m_TexStandLifeTime))) cmd = PARSERR_GENERIC;
+ else m_StandSprite = spr;
+ break;
+
+ case TOKEN_TURN_LEFT:
+ delete m_TurnLeftSprite;
+ m_TurnLeftSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true))) cmd = PARSERR_GENERIC;
+ else m_TurnLeftSprite = spr;
+ break;
+
+ case TOKEN_TURN_RIGHT:
+ delete m_TurnRightSprite;
+ m_TurnRightSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true))) cmd = PARSERR_GENERIC;
+ else m_TurnRightSprite = spr;
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_CURSOR:
+ delete m_Cursor;
+ m_Cursor = new CBSprite(Game);
+ if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) {
+ delete m_Cursor;
+ m_Cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_SOUND_VOLUME:
+ parser.ScanStr((char *)params, "%d", &m_SFXVolume);
+ break;
+
+ case TOKEN_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ m_Scale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_RELATIVE_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ m_RelativeScale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_SOUND_PANNING:
+ parser.ScanStr((char *)params, "%b", &m_AutoSoundPanning);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_BLOCKED_REGION: {
+ delete m_BlockRegion;
+ delete m_CurrentBlockRegion;
+ m_BlockRegion = NULL;
+ m_CurrentBlockRegion = NULL;
+ CBRegion *rgn = new CBRegion(Game);
+ CBRegion *crgn = new CBRegion(Game);
+ if (!rgn || !crgn || FAILED(rgn->LoadBuffer(params, false))) {
+ delete m_BlockRegion;
+ delete m_CurrentBlockRegion;
+ m_BlockRegion = NULL;
+ m_CurrentBlockRegion = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ m_BlockRegion = rgn;
+ m_CurrentBlockRegion = crgn;
+ m_CurrentBlockRegion->Mimic(m_BlockRegion);
+ }
+ }
+ break;
+
+ case TOKEN_WAYPOINTS: {
+ delete m_WptGroup;
+ delete m_CurrentWptGroup;
+ m_WptGroup = NULL;
+ m_CurrentWptGroup = NULL;
+ CAdWaypointGroup *wpt = new CAdWaypointGroup(Game);
+ CAdWaypointGroup *cwpt = new CAdWaypointGroup(Game);
+ if (!wpt || !cwpt || FAILED(wpt->LoadBuffer(params, false))) {
+ delete m_WptGroup;
+ delete m_CurrentWptGroup;
+ m_WptGroup = NULL;
+ m_CurrentWptGroup = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ m_WptGroup = wpt;
+ m_CurrentWptGroup = cwpt;
+ m_CurrentWptGroup->Mimic(m_WptGroup);
+ }
+ }
+ break;
+
+ case TOKEN_IGNORE_ITEMS:
+ parser.ScanStr((char *)params, "%b", &m_IgnoreItems);
+ break;
+
+ case TOKEN_ALPHA_COLOR:
+ parser.ScanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab);
+ break;
+
+ case TOKEN_ALPHA:
+ parser.ScanStr((char *)params, "%d", &alpha);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+
+ case TOKEN_ANIMATION: {
+ CAdSpriteSet *Anim = new CAdSpriteSet(Game, this);
+ if (!Anim || FAILED(Anim->LoadBuffer(params, false))) cmd = PARSERR_GENERIC;
+ else m_Anims.Add(Anim);
+ }
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in ACTOR definition");
+ return E_FAIL;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ if (spr) delete spr;
+ Game->LOG(0, "Error loading ACTOR definition");
+ return E_FAIL;
+ }
+
+ if (alpha != 0 && ar == 0 && ag == 0 && ab == 0) {
+ ar = ag = ab = 255;
+ }
+ m_AlphaColor = DRGBA(ar, ag, ab, alpha);
+ m_State = m_NextState = STATE_READY;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::TurnTo(TDirection dir) {
+ int delta1, delta2, delta3, delta;
+
+ delta1 = dir - m_Dir;
+ delta2 = dir + NUM_DIRECTIONS - m_Dir;
+ delta3 = dir - NUM_DIRECTIONS - m_Dir;
+
+ delta1 = (abs(delta1) <= abs(delta2)) ? delta1 : delta2;
+ delta = (abs(delta1) <= abs(delta3)) ? delta1 : delta3;
+
+ // already there?
+ if (abs(delta) < 2) {
+ m_Dir = dir;
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ return;
+ }
+
+ m_TargetDir = dir;
+ m_State = delta < 0 ? STATE_TURNING_LEFT : STATE_TURNING_RIGHT;
+
+ m_TempSprite2 = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::GoTo(int X, int Y, TDirection AfterWalkDir) {
+ m_AfterWalkDir = AfterWalkDir;
+ if (X == m_TargetPoint->x && Y == m_TargetPoint->y && m_State == STATE_FOLLOWING_PATH) return;
+
+ m_Path->Reset();
+ m_Path->SetReady(false);
+
+ m_TargetPoint->x = X;
+ m_TargetPoint->y = Y;
+
+ ((CAdGame *)Game)->m_Scene->CorrectTargetPoint(m_PosX, m_PosY, &m_TargetPoint->x, &m_TargetPoint->y, true, this);
+
+ m_State = STATE_SEARCHING_PATH;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::Display() {
+ if (m_Active) UpdateSounds();
+
+ uint32 Alpha;
+ if (m_AlphaColor != 0) Alpha = m_AlphaColor;
+ else Alpha = m_Shadowable ? ((CAdGame *)Game)->m_Scene->GetAlphaAt(m_PosX, m_PosY, true) : 0xFFFFFFFF;
+
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+
+ float Rotate;
+ if (m_Rotatable) {
+ if (m_RotateValid) Rotate = m_Rotate;
+ else Rotate = ((CAdGame *)Game)->m_Scene->GetRotationAt(m_PosX, m_PosY) + m_RelativeRotate;
+ } else Rotate = 0.0f;
+
+ if (m_Active) DisplaySpriteAttachments(true);
+
+ if (m_CurrentSprite && m_Active) {
+ bool Reg = m_Registrable;
+ if (m_IgnoreItems && ((CAdGame *)Game)->m_SelectedItem) Reg = false;
+
+ m_CurrentSprite->Display(m_PosX,
+ m_PosY,
+ Reg ? m_RegisterAlias : NULL,
+ ScaleX,
+ ScaleY,
+ Alpha,
+ Rotate,
+ m_BlendMode);
+
+ }
+
+ if (m_Active) DisplaySpriteAttachments(false);
+ if (m_Active && m_PartEmitter) m_PartEmitter->Display();
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::Update() {
+ m_CurrentSprite = NULL;
+
+ if (m_State == STATE_READY) {
+ if (m_AnimSprite) {
+ delete m_AnimSprite;
+ m_AnimSprite = NULL;
+ }
+ if (m_AnimSprite2) {
+ m_AnimSprite2 = NULL;
+ }
+ }
+
+ // finished playing animation?
+ if (m_State == STATE_PLAYING_ANIM && m_AnimSprite != NULL && m_AnimSprite->m_Finished) {
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ m_CurrentSprite = m_AnimSprite;
+ }
+
+ if (m_State == STATE_PLAYING_ANIM_SET && m_AnimSprite2 != NULL && m_AnimSprite2->m_Finished) {
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ m_CurrentSprite = m_AnimSprite2;
+ }
+
+ if (m_Sentence && m_State != STATE_TALKING) m_Sentence->Finish();
+
+ // default: stand animation
+ if (!m_CurrentSprite) {
+ if (m_Sprite) m_CurrentSprite = m_Sprite;
+ else {
+ if (m_StandSprite) {
+ m_CurrentSprite = m_StandSprite->GetSprite(m_Dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(m_IdleAnimName);
+ if (Anim) m_CurrentSprite = Anim->GetSprite(m_Dir);
+ }
+ }
+ }
+
+ bool already_moved = false;
+
+ switch (m_State) {
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM:
+ m_CurrentSprite = m_AnimSprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM_SET:
+ m_CurrentSprite = m_AnimSprite2;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TURNING_LEFT:
+ if (m_TempSprite2 == NULL || m_TempSprite2->m_Finished) {
+ if (m_Dir > 0) m_Dir = (TDirection)(m_Dir - 1);
+ else m_Dir = (TDirection)(NUM_DIRECTIONS - 1);
+
+ if (m_Dir == m_TargetDir) {
+ m_TempSprite2 = NULL;
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ } else {
+ if (m_TurnLeftSprite) {
+ m_TempSprite2 = m_TurnLeftSprite->GetSprite(m_Dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(m_TurnLeftAnimName);
+ if (Anim) m_TempSprite2 = Anim->GetSprite(m_Dir);
+ }
+
+ if (m_TempSprite2) {
+ m_TempSprite2->Reset();
+ if (m_TempSprite2->m_Looping) m_TempSprite2->m_Looping = false;
+ }
+ m_CurrentSprite = m_TempSprite2;
+ }
+ } else m_CurrentSprite = m_TempSprite2;
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TURNING_RIGHT:
+ if (m_TempSprite2 == NULL || m_TempSprite2->m_Finished) {
+ m_Dir = (TDirection)(m_Dir + 1);
+
+ if ((int)m_Dir >= (int)NUM_DIRECTIONS) m_Dir = (TDirection)(0);
+
+ if (m_Dir == m_TargetDir) {
+ m_TempSprite2 = NULL;
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ } else {
+ if (m_TurnRightSprite) {
+ m_TempSprite2 = m_TurnRightSprite->GetSprite(m_Dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(m_TurnRightAnimName);
+ if (Anim) m_TempSprite2 = Anim->GetSprite(m_Dir);
+ }
+
+ if (m_TempSprite2) {
+ m_TempSprite2->Reset();
+ if (m_TempSprite2->m_Looping) m_TempSprite2->m_Looping = false;
+ }
+ m_CurrentSprite = m_TempSprite2;
+ }
+ } else m_CurrentSprite = m_TempSprite2;
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_SEARCHING_PATH:
+ // keep asking scene for the path
+ if (((CAdGame *)Game)->m_Scene->GetPath(CBPoint(m_PosX, m_PosY), *m_TargetPoint, m_Path, this))
+ m_State = STATE_WAITING_PATH;
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_WAITING_PATH:
+ // wait until the scene finished the path
+ if (m_Path->m_Ready) FollowPath();
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_FOLLOWING_PATH:
+ GetNextStep();
+ already_moved = true;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TALKING: {
+ m_Sentence->Update(m_Dir);
+ if (m_Sentence->m_CurrentSprite) m_TempSprite2 = m_Sentence->m_CurrentSprite;
+
+ bool TimeIsUp = (m_Sentence->m_Sound && m_Sentence->m_SoundStarted && (!m_Sentence->m_Sound->IsPlaying() && !m_Sentence->m_Sound->IsPaused())) || (!m_Sentence->m_Sound && m_Sentence->m_Duration <= Game->m_Timer - m_Sentence->m_StartTime);
+ if (m_TempSprite2 == NULL || m_TempSprite2->m_Finished || (/*m_TempSprite2->m_Looping &&*/ TimeIsUp)) {
+ if (TimeIsUp) {
+ m_Sentence->Finish();
+ m_TempSprite2 = NULL;
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ } else {
+ m_TempSprite2 = GetTalkStance(m_Sentence->GetNextStance());
+ if (m_TempSprite2) {
+ m_TempSprite2->Reset();
+ m_CurrentSprite = m_TempSprite2;
+ ((CAdGame *)Game)->AddSentence(m_Sentence);
+ }
+ }
+ } else {
+ m_CurrentSprite = m_TempSprite2;
+ ((CAdGame *)Game)->AddSentence(m_Sentence);
+ }
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_READY:
+ if (!m_AnimSprite && !m_AnimSprite2) {
+ if (m_Sprite) m_CurrentSprite = m_Sprite;
+ else {
+ if (m_StandSprite) {
+ m_CurrentSprite = m_StandSprite->GetSprite(m_Dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(m_IdleAnimName);
+ if (Anim) m_CurrentSprite = Anim->GetSprite(m_Dir);
+ }
+ }
+ }
+ break;
+ }
+
+
+ if (m_CurrentSprite && !already_moved) {
+ m_CurrentSprite->GetCurrentFrame(m_Zoomable ? ((CAdGame *)Game)->m_Scene->GetZoomAt(m_PosX, m_PosY) : 100, m_Zoomable ? ((CAdGame *)Game)->m_Scene->GetZoomAt(m_PosX, m_PosY) : 100);
+ if (m_CurrentSprite->m_Changed) {
+ m_PosX += m_CurrentSprite->m_MoveX;
+ m_PosY += m_CurrentSprite->m_MoveY;
+ AfterMove();
+ }
+ }
+
+ //Game->QuickMessageForm("%s", m_CurrentSprite->m_Filename);
+
+ UpdateBlockRegion();
+ m_Ready = (m_State == STATE_READY);
+
+ UpdatePartEmitter();
+ UpdateSpriteAttachments();
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::FollowPath() {
+ // skip current position
+ m_Path->GetFirst();
+ while (m_Path->GetCurrent() != NULL) {
+ if (m_Path->GetCurrent()->x != m_PosX || m_Path->GetCurrent()->y != m_PosY) break;
+ m_Path->GetNext();
+ }
+
+ // are there points to follow?
+ if (m_Path->GetCurrent() != NULL) {
+ m_State = STATE_FOLLOWING_PATH;;
+ InitLine(CBPoint(m_PosX, m_PosY), *m_Path->GetCurrent());
+ } else {
+ if (m_AfterWalkDir != DI_NONE) TurnTo(m_AfterWalkDir);
+ else m_State = STATE_READY;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::GetNextStep() {
+ if (m_WalkSprite) {
+ m_CurrentSprite = m_WalkSprite->GetSprite(m_Dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(m_WalkAnimName);
+ if (Anim) m_CurrentSprite = Anim->GetSprite(m_Dir);
+ }
+
+ if (!m_CurrentSprite) return;
+
+ m_CurrentSprite->GetCurrentFrame(m_Zoomable ? ((CAdGame *)Game)->m_Scene->GetZoomAt(m_PosX, m_PosY) : 100, m_Zoomable ? ((CAdGame *)Game)->m_Scene->GetZoomAt(m_PosX, m_PosY) : 100);
+ if (!m_CurrentSprite->m_Changed) return;
+
+
+ int MaxStepX, MaxStepY;
+ MaxStepX = abs(m_CurrentSprite->m_MoveX);
+ MaxStepY = abs(m_CurrentSprite->m_MoveY);
+
+ MaxStepX = std::max(MaxStepX, MaxStepY);
+ MaxStepX = std::max(MaxStepX, 1);
+
+ while (m_PFCount > 0 && MaxStepX >= 0) {
+ m_PFX += m_PFStepX;
+ m_PFY += m_PFStepY;
+
+ m_PFCount--;
+ MaxStepX--;
+ }
+
+ if (((CAdGame *)Game)->m_Scene->IsBlockedAt(m_PFX, m_PFY, true, this)) {
+ if (m_PFCount == 0) {
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ return;
+ }
+ GoTo(m_TargetPoint->x, m_TargetPoint->y);
+ return;
+ }
+
+
+ m_PosX = (int)m_PFX;
+ m_PosY = (int)m_PFY;
+
+ AfterMove();
+
+
+ if (m_PFCount == 0) {
+ if (m_Path->GetNext() == NULL) {
+ m_PosX = m_TargetPoint->x;
+ m_PosY = m_TargetPoint->y;
+
+ m_Path->Reset();
+ if (m_AfterWalkDir != DI_NONE) TurnTo(m_AfterWalkDir);
+ else {
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ }
+ } else InitLine(CBPoint(m_PosX, m_PosY), *m_Path->GetCurrent());
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::InitLine(CBPoint StartPt, CBPoint EndPt) {
+ m_PFCount = std::max((abs(EndPt.x - StartPt.x)) , (abs(EndPt.y - StartPt.y)));
+
+ m_PFStepX = (double)(EndPt.x - StartPt.x) / m_PFCount;
+ m_PFStepY = (double)(EndPt.y - StartPt.y) / m_PFCount;
+
+ m_PFX = StartPt.x;
+ m_PFY = StartPt.y;
+
+ int angle = (int)(atan2((double)(EndPt.y - StartPt.y), (double)(EndPt.x - StartPt.x)) * (180 / 3.14));
+
+ m_NextState = STATE_FOLLOWING_PATH;
+
+ TurnTo(AngleToDirection(angle));
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // GoTo / GoToAsync
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "GoTo") == 0 || strcmp(Name, "GoToAsync") == 0) {
+ Stack->CorrectParams(2);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+ GoTo(X, Y);
+ if (strcmp(Name, "GoToAsync") != 0) Script->WaitForExclusive(this);
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GoToObject / GoToObjectAsync
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GoToObject") == 0 || strcmp(Name, "GoToObjectAsync") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+ if (!Val->IsNative()) {
+ Script->RuntimeError("actor.%s method accepts an entity refrence only", Name);
+ Stack->PushNULL();
+ return S_OK;
+ }
+ CAdObject *Obj = (CAdObject *)Val->GetNative();
+ if (!Obj || Obj->m_Type != OBJECT_ENTITY) {
+ Script->RuntimeError("actor.%s method accepts an entity refrence only", Name);
+ Stack->PushNULL();
+ return S_OK;
+ }
+ CAdEntity *Ent = (CAdEntity *)Obj;
+ if (Ent->m_WalkToX == 0 && Ent->m_WalkToY == 0) GoTo(Ent->m_PosX, Ent->m_PosY);
+ else GoTo(Ent->m_WalkToX, Ent->m_WalkToY, Ent->m_WalkToDir);
+ if (strcmp(Name, "GoToObjectAsync") != 0) Script->WaitForExclusive(this);
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnTo / TurnToAsync
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnTo") == 0 || strcmp(Name, "TurnToAsync") == 0) {
+ Stack->CorrectParams(1);
+ int dir;
+ CScValue *val = Stack->Pop();
+
+ // turn to object?
+ if (val->IsNative() && Game->ValidObject((CBObject *)val->GetNative())) {
+ CBObject *obj = (CBObject *)val->GetNative();
+ int angle = (int)(atan2((double)(obj->m_PosY - m_PosY), (double)(obj->m_PosX - m_PosX)) * (180 / 3.14));
+ dir = (int)AngleToDirection(angle);
+ }
+ // otherwise turn to direction
+ else dir = val->GetInt();
+
+ if (dir >= 0 && dir < NUM_DIRECTIONS) {
+ TurnTo((TDirection)dir);
+ if (strcmp(Name, "TurnToAsync") != 0) Script->WaitForExclusive(this);
+ }
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsWalking
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsWalking") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(m_State == STATE_FOLLOWING_PATH);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MergeAnims
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MergeAnims") == 0) {
+ Stack->CorrectParams(1);
+ Stack->PushBool(SUCCEEDED(MergeAnims(Stack->Pop()->GetString())));
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // UnloadAnim
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "UnloadAnim") == 0) {
+ Stack->CorrectParams(1);
+ char *AnimName = Stack->Pop()->GetString();
+
+ bool Found = false;
+ for (int i = 0; i < m_Anims.GetSize(); i++) {
+ if (scumm_stricmp(m_Anims[i]->m_Name, AnimName) == 0) {
+ // invalidate sprites in use
+ if (m_Anims[i]->ContainsSprite(m_TempSprite2)) m_TempSprite2 = NULL;
+ if (m_Anims[i]->ContainsSprite(m_CurrentSprite)) m_CurrentSprite = NULL;
+ if (m_Anims[i]->ContainsSprite(m_AnimSprite2)) m_AnimSprite2 = NULL;
+
+ delete m_Anims[i];
+ m_Anims[i] = NULL;
+ m_Anims.RemoveAt(i);
+ i--;
+ Found = true;
+ }
+ }
+ Stack->PushBool(Found);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HasAnim
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "HasAnim") == 0) {
+ Stack->CorrectParams(1);
+ char *AnimName = Stack->Pop()->GetString();
+ Stack->PushBool(GetAnimByName(AnimName) != NULL);
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdActor::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Direction
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Direction") == 0) {
+ m_ScValue->SetInt(m_Dir);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("actor");
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // TalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TalkAnimName") == 0) {
+ m_ScValue->SetString(m_TalkAnimName);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkAnimName") == 0) {
+ m_ScValue->SetString(m_WalkAnimName);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IdleAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IdleAnimName") == 0) {
+ m_ScValue->SetString(m_IdleAnimName);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnLeftAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnLeftAnimName") == 0) {
+ m_ScValue->SetString(m_TurnLeftAnimName);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnRightAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnRightAnimName") == 0) {
+ m_ScValue->SetString(m_TurnRightAnimName);
+ return m_ScValue;
+ }
+
+ else return CAdTalkHolder::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::ScSetProperty(char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Direction
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Direction") == 0) {
+ int dir = Value->GetInt();
+ if (dir >= 0 && dir < NUM_DIRECTIONS) m_Dir = (TDirection)dir;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TalkAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&m_TalkAnimName, "talk");
+ else CBUtils::SetString(&m_TalkAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&m_WalkAnimName, "walk");
+ else CBUtils::SetString(&m_WalkAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IdleAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IdleAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&m_IdleAnimName, "idle");
+ else CBUtils::SetString(&m_IdleAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnLeftAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnLeftAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&m_TurnLeftAnimName, "turnleft");
+ else CBUtils::SetString(&m_TurnLeftAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnRightAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnRightAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&m_TurnRightAnimName, "turnright");
+ else CBUtils::SetString(&m_TurnRightAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdActor::ScToString() {
+ return "[actor object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdActor::GetTalkStance(char *Stance) {
+ // forced stance?
+ if (m_ForcedTalkAnimName && !m_ForcedTalkAnimUsed) {
+ m_ForcedTalkAnimUsed = true;
+ delete m_AnimSprite;
+ m_AnimSprite = new CBSprite(Game, this);
+ if (m_AnimSprite) {
+ HRESULT res = m_AnimSprite->LoadFile(m_ForcedTalkAnimName);
+ if (FAILED(res)) {
+ Game->LOG(res, "CAdActor::GetTalkStance: error loading talk sprite (object:\"%s\" sprite:\"%s\")", m_Name, m_ForcedTalkAnimName);
+ delete m_AnimSprite;
+ m_AnimSprite = NULL;
+ } else return m_AnimSprite;
+ }
+ }
+
+ // old way
+ if (m_TalkSprites.GetSize() > 0 || m_TalkSpritesEx.GetSize() > 0)
+ return GetTalkStanceOld(Stance);
+
+ // new way
+ CBSprite *Ret = NULL;
+
+ // do we have an animation with this name?
+ CAdSpriteSet *Anim = GetAnimByName(Stance);
+ if (Anim) Ret = Anim->GetSprite(m_Dir);
+
+ // not - get a random talk
+ if (!Ret) {
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> TalkAnims;
+ for (int i = 0; i < m_Anims.GetSize(); i++) {
+ if (scumm_stricmp(m_Anims[i]->m_Name, m_TalkAnimName) == 0)
+ TalkAnims.Add(m_Anims[i]);
+ }
+
+ if (TalkAnims.GetSize() > 0) {
+ int rnd = rand() % TalkAnims.GetSize();
+ Ret = TalkAnims[rnd]->GetSprite(m_Dir);
+ } else {
+ if (m_StandSprite) Ret = m_StandSprite->GetSprite(m_Dir);
+ else {
+ Anim = GetAnimByName(m_IdleAnimName);
+ if (Anim) Ret = Anim->GetSprite(m_Dir);
+ }
+ }
+ }
+ return Ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdActor::GetTalkStanceOld(char *Stance) {
+ CBSprite *ret = NULL;
+
+ if (Stance != NULL) {
+ // search special stances
+ for (int i = 0; i < m_TalkSpritesEx.GetSize(); i++) {
+ if (scumm_stricmp(m_TalkSpritesEx[i]->m_Name, Stance) == 0) {
+ ret = m_TalkSpritesEx[i]->GetSprite(m_Dir);
+ break;
+ }
+ }
+ if (ret == NULL) {
+ // search generic stances
+ for (int i = 0; i < m_TalkSprites.GetSize(); i++) {
+ if (scumm_stricmp(m_TalkSprites[i]->m_Name, Stance) == 0) {
+ ret = m_TalkSprites[i]->GetSprite(m_Dir);
+ break;
+ }
+ }
+ }
+ }
+
+ // not a valid stance? get a random one
+ if (ret == NULL) {
+ if (m_TalkSprites.GetSize() < 1) ret = m_StandSprite->GetSprite(m_Dir);
+ else {
+ // TODO: remember last
+ int rnd = rand() % m_TalkSprites.GetSize();
+ ret = m_TalkSprites[rnd]->GetSprite(m_Dir);
+ }
+ }
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::Persist(CBPersistMgr *PersistMgr) {
+ CAdTalkHolder::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER_INT(m_Dir));
+ PersistMgr->Transfer(TMEMBER(m_Path));
+ PersistMgr->Transfer(TMEMBER(m_PFCount));
+ PersistMgr->Transfer(TMEMBER(m_PFStepX));
+ PersistMgr->Transfer(TMEMBER(m_PFStepY));
+ PersistMgr->Transfer(TMEMBER(m_PFX));
+ PersistMgr->Transfer(TMEMBER(m_PFY));
+ PersistMgr->Transfer(TMEMBER(m_StandSprite));
+ m_TalkSprites.Persist(PersistMgr);
+ m_TalkSpritesEx.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER_INT(m_TargetDir));
+ PersistMgr->Transfer(TMEMBER_INT(m_AfterWalkDir));
+ PersistMgr->Transfer(TMEMBER(m_TargetPoint));
+ PersistMgr->Transfer(TMEMBER(m_TurnLeftSprite));
+ PersistMgr->Transfer(TMEMBER(m_TurnRightSprite));
+ PersistMgr->Transfer(TMEMBER(m_WalkSprite));
+
+ PersistMgr->Transfer(TMEMBER(m_AnimSprite2));
+ PersistMgr->Transfer(TMEMBER(m_TalkAnimName));
+ PersistMgr->Transfer(TMEMBER(m_IdleAnimName));
+ PersistMgr->Transfer(TMEMBER(m_WalkAnimName));
+ PersistMgr->Transfer(TMEMBER(m_TurnLeftAnimName));
+ PersistMgr->Transfer(TMEMBER(m_TurnRightAnimName));
+
+ m_Anims.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+TDirection CAdActor::AngleToDirection(int Angle) {
+ TDirection ret = DI_DOWN;;
+
+ if (Angle > -112 && Angle <= -67) ret = DI_UP;
+ else if (Angle > -67 && Angle <= -22) ret = DI_UPRIGHT;
+ else if (Angle > -22 && Angle <= 22) ret = DI_RIGHT;
+ else if (Angle > 22 && Angle <= 67) ret = DI_DOWNRIGHT;
+ else if (Angle > 67 && Angle <= 112) ret = DI_DOWN;
+ else if (Angle > 112 && Angle <= 157) ret = DI_DOWNLEFT;
+ else if ((Angle > 157 && Angle <= 180) || (Angle >= -180 && Angle <= -157)) ret = DI_LEFT;
+ else if (Angle > -157 && Angle <= -112) ret = DI_UPLEFT;
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdActor::GetHeight() {
+ // if no current sprite is set, set some
+ if (m_CurrentSprite == NULL) {
+ if (m_StandSprite) m_CurrentSprite = m_StandSprite->GetSprite(m_Dir);
+ else {
+ CAdSpriteSet *Anim = GetAnimByName(m_IdleAnimName);
+ if (Anim) m_CurrentSprite = Anim->GetSprite(m_Dir);
+ }
+ }
+ // and get height
+ return CAdTalkHolder::GetHeight();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSpriteSet *CAdActor::GetAnimByName(char *AnimName) {
+ if (!AnimName) return NULL;
+
+ for (int i = 0; i < m_Anims.GetSize(); i++) {
+ if (scumm_stricmp(m_Anims[i]->m_Name, AnimName) == 0) return m_Anims[i];
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::MergeAnims(char *AnimsFilename) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ANIMATION)
+ TOKEN_TABLE_END
+
+
+ byte *FileBuffer = Game->m_FileManager->ReadWholeFile(AnimsFilename);
+ if (FileBuffer == NULL) {
+ Game->LOG(0, "CAdActor::MergeAnims failed for file '%s'", AnimsFilename);
+ return E_FAIL;
+ }
+
+ byte *Buffer = FileBuffer;
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ HRESULT Ret = S_OK;
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_ANIMATION: {
+ CAdSpriteSet *Anim = new CAdSpriteSet(Game, this);
+ if (!Anim || FAILED(Anim->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ Ret = E_FAIL;
+ } else m_Anims.Add(Anim);
+ }
+ break;
+ }
+ }
+ delete [] FileBuffer;
+ return Ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::PlayAnim(char *Filename) {
+ // if we have an anim with this name, use it
+ CAdSpriteSet *Anim = GetAnimByName(Filename);
+ if (Anim) {
+ m_AnimSprite2 = Anim->GetSprite(m_Dir);
+ if (m_AnimSprite2) {
+ m_AnimSprite2->Reset();
+ m_State = STATE_PLAYING_ANIM_SET;
+ return S_OK;
+ }
+ }
+ // otherwise call the standard handler
+ return CAdTalkHolder::PlayAnim(Filename);
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdActor.h b/engines/wintermute/AdActor.h
new file mode 100644
index 0000000000..fa6f771a35
--- /dev/null
+++ b/engines/wintermute/AdActor.h
@@ -0,0 +1,107 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdActor_H__
+#define __WmeAdActor_H__
+
+
+#include "dctypes.h" // Added by ClassView
+#include "AdTypes.h" // Added by ClassView
+#include "AdTalkHolder.h"
+#include "BPoint.h" // Added by ClassView
+#include "persistent.h"
+#include "common/str.h"
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+namespace WinterMute {
+class CAdSpriteSet;
+class CAdPath;
+class CAdActor : public CAdTalkHolder {
+public:
+ TDirection AngleToDirection(int Angle);
+ DECLARE_PERSISTENT(CAdActor, CAdTalkHolder)
+ virtual int GetHeight();
+ CBSprite *GetTalkStance(char *Stance);
+ virtual void GoTo(int X, int Y, TDirection AfterWalkDir = DI_NONE);
+ CBPoint *m_TargetPoint;
+ virtual HRESULT Update();
+ virtual HRESULT Display();
+ TDirection m_TargetDir;
+ TDirection m_AfterWalkDir;
+ virtual void TurnTo(TDirection dir);
+ CAdPath *m_Path;
+ CAdSpriteSet *m_WalkSprite;
+ CAdSpriteSet *m_StandSprite;
+ CAdSpriteSet *m_TurnLeftSprite;
+ CAdSpriteSet *m_TurnRightSprite;
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> m_TalkSprites;
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> m_TalkSpritesEx;
+ TDirection m_Dir;
+ CAdActor(CBGame *inGame/*=NULL*/);
+ virtual ~CAdActor();
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+
+ // new anim system
+ char *m_TalkAnimName;
+ char *m_IdleAnimName;
+ char *m_WalkAnimName;
+ char *m_TurnLeftAnimName;
+ char *m_TurnRightAnimName;
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> m_Anims;
+ virtual HRESULT PlayAnim(char *Filename);
+ CAdSpriteSet *GetAnimByName(char *AnimName);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(char *Name);
+ virtual HRESULT ScSetProperty(char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name);
+ virtual char *ScToString();
+
+private:
+ HRESULT SetDefaultAnimNames();
+ CBSprite *GetTalkStanceOld(char *Stance);
+ HRESULT MergeAnims(char *AnimsFilename);
+ CBSprite *m_AnimSprite2;
+
+ void InitLine(CBPoint StartPt, CBPoint EndPt);
+ void GetNextStep();
+ void FollowPath();
+ double m_PFStepX;
+ double m_PFStepY;
+ double m_PFX;
+ double m_PFY;
+ int m_PFCount;
+};
+
+} // end of namespace WinterMute
+
+#endif // __WmeAdActor_H__
diff --git a/engines/wintermute/AdActorDir.cpp b/engines/wintermute/AdActorDir.cpp
new file mode 100644
index 0000000000..bd888ccb03
--- /dev/null
+++ b/engines/wintermute/AdActorDir.cpp
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+#include "AdActorDir.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdActorDir, false)
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdActorDir::CAdActorDir(CBGame *inGame): CBBase(inGame) {
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdActorDir::~CAdActorDir(void) {
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActorDir::Persist(CBPersistMgr *PersistMgr) {
+ //PersistMgr->Transfer(TMEMBER(x));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdActorDir.h b/engines/wintermute/AdActorDir.h
new file mode 100644
index 0000000000..6690796e5c
--- /dev/null
+++ b/engines/wintermute/AdActorDir.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdActorDir_H__
+#define __WmeAdActorDir_H__
+
+#include "persistent.h"
+#include "BBase.h"
+
+namespace WinterMute {
+
+class CAdActorDir : public CBBase {
+public:
+ DECLARE_PERSISTENT(CAdActorDir, CBBase)
+ CAdActorDir(CBGame *inGame);
+ virtual ~CAdActorDir(void);
+};
+
+} // end of namespace WinterMute
+
+#endif // __WmeAdActorDir_H__ \ No newline at end of file
diff --git a/engines/wintermute/AdEntity.cpp b/engines/wintermute/AdEntity.cpp
new file mode 100644
index 0000000000..c4827cfeed
--- /dev/null
+++ b/engines/wintermute/AdEntity.cpp
@@ -0,0 +1,959 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdEntity.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "BActiveRect.h"
+#include "BSurfaceStorage.h"
+#include "ScValue.h"
+#include "BGame.h"
+#include "AdGame.h"
+#include "AdScene.h"
+#include "BSound.h"
+#include "AdWaypointGroup.h"
+#include "BFontStorage.h"
+#include "BFont.h"
+#include "AdSentence.h"
+#include "ScScript.h"
+#include "ScStack.h"
+#include "BRegion.h"
+#include "BSprite.h"
+#include "BFileManager.h"
+#include "PlatformSDL.h"
+#include "utils.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdEntity, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdEntity::CAdEntity(CBGame *inGame): CAdTalkHolder(inGame) {
+ m_Type = OBJECT_ENTITY;
+ m_Subtype = ENTITY_NORMAL;
+ m_Region = NULL;
+ m_Item = NULL;
+
+ m_WalkToX = m_WalkToY = 0;
+ m_WalkToDir = DI_NONE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdEntity::~CAdEntity() {
+ Game->UnregisterObject(m_Region);
+
+ delete[] m_Item;
+ m_Item = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdEntity::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing ENTITY file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(ENTITY)
+TOKEN_DEF(SPRITE)
+TOKEN_DEF(X)
+TOKEN_DEF(Y)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(NAME)
+TOKEN_DEF(SCALABLE)
+TOKEN_DEF(REGISTRABLE)
+TOKEN_DEF(INTERACTIVE)
+TOKEN_DEF(SHADOWABLE)
+TOKEN_DEF(COLORABLE)
+TOKEN_DEF(ACTIVE)
+TOKEN_DEF(EVENTS)
+TOKEN_DEF(FONT)
+TOKEN_DEF(TALK_SPECIAL)
+TOKEN_DEF(TALK)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(REGION)
+TOKEN_DEF(BLOCKED_REGION)
+TOKEN_DEF(EDITOR_SELECTED)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(SOUND_START_TIME)
+TOKEN_DEF(SOUND_VOLUME)
+TOKEN_DEF(SOUND_PANNING)
+TOKEN_DEF(SOUND)
+TOKEN_DEF(SUBTYPE)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PROPERTY)
+TOKEN_DEF(WAYPOINTS)
+TOKEN_DEF(IGNORE_ITEMS)
+TOKEN_DEF(ROTABLE)
+TOKEN_DEF(ROTATABLE)
+TOKEN_DEF(ALPHA_COLOR)
+TOKEN_DEF(SCALE)
+TOKEN_DEF(RELATIVE_SCALE)
+TOKEN_DEF(ALPHA)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF(ITEM)
+TOKEN_DEF(WALK_TO_X)
+TOKEN_DEF(WALK_TO_Y)
+TOKEN_DEF(WALK_TO_DIR)
+TOKEN_DEF(SAVE_STATE)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ENTITY)
+ TOKEN_TABLE(SPRITE)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(SCALABLE)
+ TOKEN_TABLE(REGISTRABLE)
+ TOKEN_TABLE(INTERACTIVE)
+ TOKEN_TABLE(SHADOWABLE)
+ TOKEN_TABLE(COLORABLE)
+ TOKEN_TABLE(ACTIVE)
+ TOKEN_TABLE(EVENTS)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(TALK_SPECIAL)
+ TOKEN_TABLE(TALK)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(REGION)
+ TOKEN_TABLE(BLOCKED_REGION)
+ TOKEN_TABLE(EDITOR_SELECTED)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(SOUND_START_TIME)
+ TOKEN_TABLE(SOUND_VOLUME)
+ TOKEN_TABLE(SOUND_PANNING)
+ TOKEN_TABLE(SOUND)
+ TOKEN_TABLE(SUBTYPE)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PROPERTY)
+ TOKEN_TABLE(WAYPOINTS)
+ TOKEN_TABLE(IGNORE_ITEMS)
+ TOKEN_TABLE(ROTABLE)
+ TOKEN_TABLE(ROTATABLE)
+ TOKEN_TABLE(ALPHA_COLOR)
+ TOKEN_TABLE(SCALE)
+ TOKEN_TABLE(RELATIVE_SCALE)
+ TOKEN_TABLE(ALPHA)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE(ITEM)
+ TOKEN_TABLE(WALK_TO_X)
+ TOKEN_TABLE(WALK_TO_Y)
+ TOKEN_TABLE(WALK_TO_DIR)
+ TOKEN_TABLE(SAVE_STATE)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_ENTITY) {
+ Game->LOG(0, "'ENTITY' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ CAdGame *AdGame = (CAdGame *)Game;
+ CBSprite *spr = NULL;
+ int ar = 0, ag = 0, ab = 0, alpha = 0;
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_X:
+ parser.ScanStr((char *)params, "%d", &m_PosX);
+ break;
+
+ case TOKEN_Y:
+ parser.ScanStr((char *)params, "%d", &m_PosY);
+ break;
+
+ case TOKEN_SPRITE: {
+ SAFE_DELETE(m_Sprite);
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ else m_Sprite = spr;
+ }
+ break;
+
+ case TOKEN_TALK: {
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, AdGame->m_TexTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else m_TalkSprites.Add(spr);
+ }
+ break;
+
+ case TOKEN_TALK_SPECIAL: {
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, AdGame->m_TexTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else m_TalkSpritesEx.Add(spr);
+ }
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_ITEM:
+ SetItem((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ SetCaption((char *)params);
+ break;
+
+ case TOKEN_FONT:
+ SetFont((char *)params);
+ break;
+
+ case TOKEN_SCALABLE:
+ parser.ScanStr((char *)params, "%b", &m_Zoomable);
+ break;
+
+ case TOKEN_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ m_Scale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_RELATIVE_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ m_RelativeScale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_ROTABLE:
+ case TOKEN_ROTATABLE:
+ parser.ScanStr((char *)params, "%b", &m_Rotatable);
+ break;
+
+ case TOKEN_REGISTRABLE:
+ case TOKEN_INTERACTIVE:
+ parser.ScanStr((char *)params, "%b", &m_Registrable);
+ break;
+
+ case TOKEN_SHADOWABLE:
+ case TOKEN_COLORABLE:
+ parser.ScanStr((char *)params, "%b", &m_Shadowable);
+ break;
+
+ case TOKEN_ACTIVE:
+ parser.ScanStr((char *)params, "%b", &m_Active);
+ break;
+
+ case TOKEN_CURSOR:
+ SAFE_DELETE(m_Cursor);
+ m_Cursor = new CBSprite(Game);
+ if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) {
+ SAFE_DELETE(m_Cursor);
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_EDITOR_SELECTED:
+ parser.ScanStr((char *)params, "%b", &m_EditorSelected);
+ break;
+
+ case TOKEN_REGION: {
+ if (m_Region) Game->UnregisterObject(m_Region);
+ m_Region = NULL;
+ CBRegion *rgn = new CBRegion(Game);
+ if (!rgn || FAILED(rgn->LoadBuffer(params, false))) cmd = PARSERR_GENERIC;
+ else {
+ m_Region = rgn;
+ Game->RegisterObject(m_Region);
+ }
+ }
+ break;
+
+ case TOKEN_BLOCKED_REGION: {
+ SAFE_DELETE(m_BlockRegion);
+ SAFE_DELETE(m_CurrentBlockRegion);
+ CBRegion *rgn = new CBRegion(Game);
+ CBRegion *crgn = new CBRegion(Game);
+ if (!rgn || !crgn || FAILED(rgn->LoadBuffer(params, false))) {
+ SAFE_DELETE(m_BlockRegion);
+ SAFE_DELETE(m_CurrentBlockRegion);
+ cmd = PARSERR_GENERIC;
+ } else {
+ m_BlockRegion = rgn;
+ m_CurrentBlockRegion = crgn;
+ m_CurrentBlockRegion->Mimic(m_BlockRegion);
+ }
+ }
+ break;
+
+ case TOKEN_WAYPOINTS: {
+ SAFE_DELETE(m_WptGroup);
+ SAFE_DELETE(m_CurrentWptGroup);
+ CAdWaypointGroup *wpt = new CAdWaypointGroup(Game);
+ CAdWaypointGroup *cwpt = new CAdWaypointGroup(Game);
+ if (!wpt || !cwpt || FAILED(wpt->LoadBuffer(params, false))) {
+ SAFE_DELETE(m_WptGroup);
+ SAFE_DELETE(m_CurrentWptGroup);
+ cmd = PARSERR_GENERIC;
+ } else {
+ m_WptGroup = wpt;
+ m_CurrentWptGroup = cwpt;
+ m_CurrentWptGroup->Mimic(m_WptGroup);
+ }
+ }
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_SUBTYPE: {
+ if (scumm_stricmp((char *)params, "sound") == 0) {
+ SAFE_DELETE(m_Sprite);
+ if (Game->m_EditorMode) {
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile("entity_sound.sprite"))) cmd = PARSERR_GENERIC;
+ else m_Sprite = spr;
+ }
+ if (Game->m_EditorMode) m_EditorOnly = true;
+ m_Zoomable = false;
+ m_Rotatable = false;
+ m_Registrable = Game->m_EditorMode;
+ m_Shadowable = false;
+ m_Subtype = ENTITY_SOUND;
+ }
+ }
+ break;
+
+ case TOKEN_SOUND:
+ PlaySFX((char *)params, false, false);
+ break;
+
+ case TOKEN_SOUND_START_TIME:
+ parser.ScanStr((char *)params, "%d", &m_SFXStart);
+ break;
+
+ case TOKEN_SOUND_VOLUME:
+ parser.ScanStr((char *)params, "%d", &m_SFXVolume);
+ break;
+
+ case TOKEN_SOUND_PANNING:
+ parser.ScanStr((char *)params, "%b", &m_AutoSoundPanning);
+ break;
+
+ case TOKEN_SAVE_STATE:
+ parser.ScanStr((char *)params, "%b", &m_SaveState);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_IGNORE_ITEMS:
+ parser.ScanStr((char *)params, "%b", &m_IgnoreItems);
+ break;
+
+ case TOKEN_ALPHA_COLOR:
+ parser.ScanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab);
+ break;
+
+ case TOKEN_ALPHA:
+ parser.ScanStr((char *)params, "%d", &alpha);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+
+ case TOKEN_WALK_TO_X:
+ parser.ScanStr((char *)params, "%d", &m_WalkToX);
+ break;
+
+ case TOKEN_WALK_TO_Y:
+ parser.ScanStr((char *)params, "%d", &m_WalkToY);
+ break;
+
+ case TOKEN_WALK_TO_DIR: {
+ int i;
+ parser.ScanStr((char *)params, "%d", &i);
+ if (i < 0) i = 0;
+ if (i >= NUM_DIRECTIONS) i = DI_NONE;
+ m_WalkToDir = (TDirection)i;
+ }
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in ENTITY definition");
+ return E_FAIL;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading ENTITY definition");
+ if (spr) delete spr;
+ return E_FAIL;
+ }
+
+ if (m_Region && m_Sprite) {
+ Game->LOG(0, "Warning: Entity '%s' has both sprite and region.", m_Name);
+ }
+
+ UpdatePosition();
+
+ if (alpha != 0 && ar == 0 && ag == 0 && ab == 0) {
+ ar = ag = ab = 255;
+ }
+ m_AlphaColor = DRGBA(ar, ag, ab, alpha);
+ m_State = STATE_READY;
+
+ if (m_Item && ((CAdGame *)Game)->IsItemTaken(m_Item)) m_Active = false;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::Display() {
+ if (m_Active) {
+ UpdateSounds();
+
+ uint32 Alpha;
+ if (m_AlphaColor != 0) Alpha = m_AlphaColor;
+ else Alpha = m_Shadowable ? ((CAdGame *)Game)->m_Scene->GetAlphaAt(m_PosX, m_PosY) : 0xFFFFFFFF;
+
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+ float Rotate;
+ if (m_Rotatable) {
+ if (m_RotateValid) Rotate = m_Rotate;
+ else Rotate = ((CAdGame *)Game)->m_Scene->GetRotationAt(m_PosX, m_PosY) + m_RelativeRotate;
+ } else Rotate = 0.0f;
+
+
+ bool Reg = m_Registrable;
+ if (m_IgnoreItems && ((CAdGame *)Game)->m_SelectedItem) Reg = false;
+
+ if (m_Region && (Reg || m_EditorAlwaysRegister)) {
+ Game->m_Renderer->m_RectList.Add(new CBActiveRect(Game, m_RegisterAlias, m_Region, Game->m_OffsetX, Game->m_OffsetY));
+ }
+
+ DisplaySpriteAttachments(true);
+ if (m_CurrentSprite) {
+ m_CurrentSprite->Display(m_PosX,
+ m_PosY,
+ (Reg || m_EditorAlwaysRegister) ? m_RegisterAlias : NULL,
+ ScaleX,
+ ScaleY,
+ Alpha,
+ Rotate,
+ m_BlendMode);
+ }
+ DisplaySpriteAttachments(false);
+
+ if (m_PartEmitter) m_PartEmitter->Display(m_Region);
+
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::Update() {
+ m_CurrentSprite = NULL;
+
+ if (m_State == STATE_READY && m_AnimSprite) {
+ SAFE_DELETE(m_AnimSprite);
+ }
+
+ // finished playing animation?
+ if (m_State == STATE_PLAYING_ANIM && m_AnimSprite != NULL && m_AnimSprite->m_Finished) {
+ m_State = STATE_READY;
+ m_CurrentSprite = m_AnimSprite;
+ }
+
+ if (m_Sentence && m_State != STATE_TALKING) m_Sentence->Finish();
+
+ // default: stand animation
+ if (!m_CurrentSprite) m_CurrentSprite = m_Sprite;
+
+ switch (m_State) {
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM:
+ m_CurrentSprite = m_AnimSprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_READY:
+ if (!m_AnimSprite)
+ m_CurrentSprite = m_Sprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TALKING: {
+ m_Sentence->Update();
+ if (m_Sentence->m_CurrentSprite) m_TempSprite2 = m_Sentence->m_CurrentSprite;
+
+ bool TimeIsUp = (m_Sentence->m_Sound && m_Sentence->m_SoundStarted && (!m_Sentence->m_Sound->IsPlaying() && !m_Sentence->m_Sound->IsPaused())) || (!m_Sentence->m_Sound && m_Sentence->m_Duration <= Game->m_Timer - m_Sentence->m_StartTime);
+ if (m_TempSprite2 == NULL || m_TempSprite2->m_Finished || (/*m_TempSprite2->m_Looping &&*/ TimeIsUp)) {
+ if (TimeIsUp) {
+ m_Sentence->Finish();
+ m_TempSprite2 = NULL;
+ m_State = STATE_READY;
+ } else {
+ m_TempSprite2 = GetTalkStance(m_Sentence->GetNextStance());
+ if (m_TempSprite2) {
+ m_TempSprite2->Reset();
+ m_CurrentSprite = m_TempSprite2;
+ }
+ ((CAdGame *)Game)->AddSentence(m_Sentence);
+ }
+ } else {
+ m_CurrentSprite = m_TempSprite2;
+ ((CAdGame *)Game)->AddSentence(m_Sentence);
+ }
+ }
+ break;
+ }
+
+
+ if (m_CurrentSprite) {
+ m_CurrentSprite->GetCurrentFrame(m_Zoomable ? ((CAdGame *)Game)->m_Scene->GetZoomAt(m_PosX, m_PosY) : 100);
+ if (m_CurrentSprite->m_Changed) {
+ m_PosX += m_CurrentSprite->m_MoveX;
+ m_PosY += m_CurrentSprite->m_MoveY;
+ }
+ }
+
+ UpdateBlockRegion();
+ m_Ready = (m_State == STATE_READY);
+
+
+ UpdatePartEmitter();
+ UpdateSpriteAttachments();
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // StopSound
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "StopSound") == 0 && m_Subtype == ENTITY_SOUND) {
+ Stack->CorrectParams(0);
+
+ if (FAILED(StopSFX(false))) Stack->PushBool(false);
+ else Stack->PushBool(true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PlayTheora
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PlayTheora") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StopTheora
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StopTheora") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsTheoraPlaying
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsTheoraPlaying") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PauseTheora
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PauseTheora") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ResumeTheora
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ResumeTheora") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsTheoraPaused
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsTheoraPaused") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateRegion
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CreateRegion") == 0) {
+ Stack->CorrectParams(0);
+ if (!m_Region) {
+ m_Region = new CBRegion(Game);
+ Game->RegisterObject(m_Region);
+ }
+ if (m_Region) Stack->PushNative(m_Region, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteRegion
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DeleteRegion") == 0) {
+ Stack->CorrectParams(0);
+ if (m_Region) {
+ Game->UnregisterObject(m_Region);
+ m_Region = NULL;
+ Stack->PushBool(true);
+ } else Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdEntity::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type (RO)
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("entity");
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Item
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Item") == 0) {
+ if (m_Item) m_ScValue->SetString(m_Item);
+ else m_ScValue->SetNULL();
+
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Subtype (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Subtype") == 0) {
+ if (m_Subtype == ENTITY_SOUND)
+ m_ScValue->SetString("sound");
+ else
+ m_ScValue->SetString("normal");
+
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToX") == 0) {
+ m_ScValue->SetInt(m_WalkToX);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToY") == 0) {
+ m_ScValue->SetInt(m_WalkToY);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToDirection
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToDirection") == 0) {
+ m_ScValue->SetInt((int)m_WalkToDir);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Region (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Region") == 0) {
+ if (m_Region) m_ScValue->SetNative(m_Region, true);
+ else m_ScValue->SetNULL();
+ return m_ScValue;
+ }
+
+ else return CAdTalkHolder::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::ScSetProperty(char *Name, CScValue *Value) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Item
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Item") == 0) {
+ SetItem(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToX") == 0) {
+ m_WalkToX = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToY") == 0) {
+ m_WalkToY = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToDirection
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToDirection") == 0) {
+ int Dir = Value->GetInt();
+ if (Dir >= 0 && Dir < NUM_DIRECTIONS) m_WalkToDir = (TDirection)Dir;
+ return S_OK;
+ }
+
+
+ else return CAdTalkHolder::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdEntity::ScToString() {
+ return "[entity object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "ENTITY {\n");
+ Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", m_Name);
+ if (m_Subtype == ENTITY_SOUND)
+ Buffer->PutTextIndent(Indent + 2, "SUBTYPE=\"SOUND\"\n");
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+ Buffer->PutTextIndent(Indent + 2, "ACTIVE=%s\n", m_Active ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "X=%d\n", m_PosX);
+ Buffer->PutTextIndent(Indent + 2, "Y=%d\n", m_PosY);
+ Buffer->PutTextIndent(Indent + 2, "SCALABLE=%s\n", m_Zoomable ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "INTERACTIVE=%s\n", m_Registrable ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "COLORABLE=%s\n", m_Shadowable ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", m_EditorSelected ? "TRUE" : "FALSE");
+ if (m_IgnoreItems)
+ Buffer->PutTextIndent(Indent + 2, "IGNORE_ITEMS=%s\n", m_IgnoreItems ? "TRUE" : "FALSE");
+ if (m_Rotatable)
+ Buffer->PutTextIndent(Indent + 2, "ROTATABLE=%s\n", m_Rotatable ? "TRUE" : "FALSE");
+
+ if (!m_AutoSoundPanning)
+ Buffer->PutTextIndent(Indent + 2, "SOUND_PANNING=%s\n", m_AutoSoundPanning ? "TRUE" : "FALSE");
+
+ if (!m_SaveState)
+ Buffer->PutTextIndent(Indent + 2, "SAVE_STATE=%s\n", m_SaveState ? "TRUE" : "FALSE");
+
+ if (m_Item && m_Item[0] != '\0') Buffer->PutTextIndent(Indent + 2, "ITEM=\"%s\"\n", m_Item);
+
+ Buffer->PutTextIndent(Indent + 2, "WALK_TO_X=%d\n", m_WalkToX);
+ Buffer->PutTextIndent(Indent + 2, "WALK_TO_Y=%d\n", m_WalkToY);
+ if (m_WalkToDir != DI_NONE)
+ Buffer->PutTextIndent(Indent + 2, "WALK_TO_DIR=%d\n", (int)m_WalkToDir);
+
+ int i;
+
+ for (i = 0; i < m_Scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_Filename);
+ }
+
+ if (m_Subtype == ENTITY_NORMAL && m_Sprite && m_Sprite->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "SPRITE=\"%s\"\n", m_Sprite->m_Filename);
+
+ if (m_Subtype == ENTITY_SOUND && m_SFX && m_SFX->m_SoundFilename) {
+ Buffer->PutTextIndent(Indent + 2, "SOUND=\"%s\"\n", m_SFX->m_SoundFilename);
+ Buffer->PutTextIndent(Indent + 2, "SOUND_START_TIME=%d\n", m_SFXStart);
+ Buffer->PutTextIndent(Indent + 2, "SOUND_VOLUME=%d\n", m_SFXVolume);
+ }
+
+
+ if (D3DCOLGetR(m_AlphaColor) != 0 || D3DCOLGetG(m_AlphaColor) != 0 || D3DCOLGetB(m_AlphaColor) != 0)
+ Buffer->PutTextIndent(Indent + 2, "ALPHA_COLOR { %d,%d,%d }\n", D3DCOLGetR(m_AlphaColor), D3DCOLGetG(m_AlphaColor), D3DCOLGetB(m_AlphaColor));
+
+ if (D3DCOLGetA(m_AlphaColor) != 0)
+ Buffer->PutTextIndent(Indent + 2, "ALPHA = %d\n", D3DCOLGetA(m_AlphaColor));
+
+ if (m_Scale >= 0)
+ Buffer->PutTextIndent(Indent + 2, "SCALE = %d\n", (int)m_Scale);
+
+ if (m_RelativeScale != 0)
+ Buffer->PutTextIndent(Indent + 2, "RELATIVE_SCALE = %d\n", (int)m_RelativeScale);
+
+ if (m_Font && m_Font->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", m_Font->m_Filename);
+
+ if (m_Cursor && m_Cursor->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", m_Cursor->m_Filename);
+
+ CAdTalkHolder::SaveAsText(Buffer, Indent + 2);
+
+ if (m_Region) m_Region->SaveAsText(Buffer, Indent + 2);
+
+ if (m_ScProp) m_ScProp->SaveAsText(Buffer, Indent + 2);
+
+ CAdObject::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdEntity::GetHeight() {
+ if (m_Region && !m_Sprite) {
+ return m_Region->m_Rect.bottom - m_Region->m_Rect.top;
+ } else {
+ if (m_CurrentSprite == NULL) m_CurrentSprite = m_Sprite;
+ return CAdObject::GetHeight();
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdEntity::UpdatePosition() {
+ if (m_Region && !m_Sprite) {
+ m_PosX = m_Region->m_Rect.left + (m_Region->m_Rect.right - m_Region->m_Rect.left) / 2;
+ m_PosY = m_Region->m_Rect.bottom;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::Persist(CBPersistMgr *PersistMgr) {
+ CAdTalkHolder::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Item));
+ PersistMgr->Transfer(TMEMBER(m_Region));
+ //PersistMgr->Transfer(TMEMBER(m_Sprite));
+ PersistMgr->Transfer(TMEMBER_INT(m_Subtype));
+ m_TalkSprites.Persist(PersistMgr);
+ m_TalkSpritesEx.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_WalkToX));
+ PersistMgr->Transfer(TMEMBER(m_WalkToY));
+ PersistMgr->Transfer(TMEMBER_INT(m_WalkToDir));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdEntity::SetItem(char *ItemName) {
+ CBUtils::SetString(&m_Item, ItemName);
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::SetSprite(char *Filename) {
+ bool SetCurrent = false;
+ if (m_CurrentSprite == m_Sprite) {
+ m_CurrentSprite = NULL;
+ SetCurrent = true;
+ }
+
+ SAFE_DELETE(m_Sprite);
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ SAFE_DELETE(m_Sprite);
+ return E_FAIL;
+ } else {
+ m_Sprite = spr;
+ m_CurrentSprite = m_Sprite;
+ return S_OK;
+ }
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdGame.cpp b/engines/wintermute/AdGame.cpp
new file mode 100644
index 0000000000..b5e8518e30
--- /dev/null
+++ b/engines/wintermute/AdGame.cpp
@@ -0,0 +1,2062 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdGame.h"
+#include "AdResponseBox.h"
+#include "AdInventoryBox.h"
+#include "AdSceneState.h"
+#include "PartEmitter.h"
+#include "BParser.h"
+#include "BSurfaceStorage.h"
+#include "BTransitionMgr.h"
+#include "BObject.h"
+#include "BSound.h"
+#include "UIWindow.h"
+#include "ScValue.h"
+#include "UIEntity.h"
+#include "AdScene.h"
+#include "AdEntity.h"
+#include "AdActor.h"
+#include "AdInventory.h"
+#include "AdResponseContext.h"
+#include "AdItem.h"
+#include "BViewport.h"
+#include "BFont.h"
+#include "ScEngine.h"
+#include "BStringTable.h"
+#include "AdSentence.h"
+#include "AdResponse.h"
+#include "ScScript.h"
+#include "ScStack.h"
+#include "BSprite.h"
+#include "BFileManager.h"
+#include "utils.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdGame, true)
+
+//////////////////////////////////////////////////////////////////////////
+CAdGame::CAdGame(): CBGame() {
+ m_ResponseBox = NULL;
+ m_InventoryBox = NULL;
+
+ m_Scene = new CAdScene(Game);
+ m_Scene->SetName("");
+ RegisterObject(m_Scene);
+
+ m_PrevSceneName = NULL;
+ m_PrevSceneFilename = NULL;
+ m_ScheduledScene = NULL;
+ m_ScheduledFadeIn = false;
+
+
+ m_StateEx = GAME_NORMAL;
+
+ m_SelectedItem = NULL;
+
+
+ m_TexItemLifeTime = 10000;
+ m_TexWalkLifeTime = 10000;
+ m_TexStandLifeTime = 10000;
+ m_TexTalkLifeTime = 10000;
+
+ m_TalkSkipButton = TALK_SKIP_LEFT;
+
+ m_SceneViewport = NULL;
+
+ m_InitialScene = true;
+ m_DebugStartupScene = NULL;
+ m_StartupScene = NULL;
+
+ m_InvObject = new CAdObject(this);
+ m_InventoryOwner = m_InvObject;
+
+ m_TempDisableSaveState = false;
+ m_ItemsFile = NULL;
+
+ m_SmartItemCursor = false;
+
+ AddSpeechDir("speech");
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdGame::~CAdGame() {
+ Cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::Cleanup() {
+ int i;
+
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ UnregisterObject(m_Objects[i]);
+ m_Objects[i] = NULL;
+ }
+ m_Objects.RemoveAll();
+
+
+ for (i = 0; i < m_DlgPendingBranches.GetSize(); i++) {
+ delete [] m_DlgPendingBranches[i];
+ }
+ m_DlgPendingBranches.RemoveAll();
+
+ for (i = 0; i < m_SpeechDirs.GetSize(); i++) {
+ delete [] m_SpeechDirs[i];
+ }
+ m_SpeechDirs.RemoveAll();
+
+
+ UnregisterObject(m_Scene);
+ m_Scene = NULL;
+
+ // remove items
+ for (i = 0; i < m_Items.GetSize(); i++) Game->UnregisterObject(m_Items[i]);
+ m_Items.RemoveAll();
+
+
+ // clear remaining inventories
+ delete m_InvObject;
+ m_InvObject = NULL;
+
+ for (i = 0; i < m_Inventories.GetSize(); i++) {
+ delete m_Inventories[i];
+ }
+ m_Inventories.RemoveAll();
+
+
+ if (m_ResponseBox) {
+ Game->UnregisterObject(m_ResponseBox);
+ m_ResponseBox = NULL;
+ }
+
+ if (m_InventoryBox) {
+ Game->UnregisterObject(m_InventoryBox);
+ m_InventoryBox = NULL;
+ }
+
+ delete[] m_PrevSceneName;
+ delete[] m_PrevSceneFilename;
+ delete[] m_ScheduledScene;
+ delete[] m_DebugStartupScene;
+ delete[] m_ItemsFile;
+ m_PrevSceneName = NULL;
+ m_PrevSceneFilename = NULL;
+ m_ScheduledScene = NULL;
+ m_DebugStartupScene = NULL;
+ m_StartupScene = NULL;
+ m_ItemsFile = NULL;
+
+ delete m_SceneViewport;
+ m_SceneViewport = NULL;
+
+ for (i = 0; i < m_SceneStates.GetSize(); i++) delete m_SceneStates[i];
+ m_SceneStates.RemoveAll();
+
+ for (i = 0; i < m_ResponsesBranch.GetSize(); i++) delete m_ResponsesBranch[i];
+ m_ResponsesBranch.RemoveAll();
+
+ for (i = 0; i < m_ResponsesGame.GetSize(); i++) delete m_ResponsesGame[i];
+ m_ResponsesGame.RemoveAll();
+
+ return CBGame::Cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::InitLoop() {
+ if (m_ScheduledScene && m_TransMgr->IsReady()) {
+ ChangeScene(m_ScheduledScene, m_ScheduledFadeIn);
+ SAFE_DELETE_ARRAY(m_ScheduledScene);
+
+ Game->m_ActiveObject = NULL;
+ }
+
+
+ HRESULT res;
+ res = CBGame::InitLoop();
+ if (FAILED(res)) return res;
+
+ if (m_Scene) res = m_Scene->InitLoop();
+
+ m_Sentences.RemoveAll();
+
+ return res;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddObject(CAdObject *Object) {
+ m_Objects.Add(Object);
+ return RegisterObject(Object);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::RemoveObject(CAdObject *Object) {
+ // in case the user called Scene.CreateXXX() and Game.DeleteXXX()
+ if (m_Scene) {
+ HRESULT Res = m_Scene->RemoveObject(Object);
+ if (SUCCEEDED(Res)) return Res;
+ }
+
+ for (int i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i] == Object) {
+ m_Objects.RemoveAt(i);
+ break;
+ }
+ }
+ return UnregisterObject(Object);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ChangeScene(char *Filename, bool FadeIn) {
+ if (m_Scene == NULL) {
+ m_Scene = new CAdScene(Game);
+ RegisterObject(m_Scene);
+ } else {
+ m_Scene->ApplyEvent("SceneShutdown", true);
+
+ SetPrevSceneName(m_Scene->m_Name);
+ SetPrevSceneFilename(m_Scene->m_Filename);
+
+ if (!m_TempDisableSaveState) m_Scene->SaveState();
+ m_TempDisableSaveState = false;
+ }
+
+ if (m_Scene) {
+ // reset objects
+ for (int i = 0; i < m_Objects.GetSize(); i++) m_Objects[i]->Reset();
+
+ // reset scene properties
+ m_Scene->m_SFXVolume = 100;
+ if (m_Scene->m_ScProp) m_Scene->m_ScProp->Cleanup();
+
+ HRESULT ret;
+ if (m_InitialScene && m_DEBUG_DebugMode && m_DebugStartupScene) {
+ m_InitialScene = false;
+ ret = m_Scene->LoadFile(m_DebugStartupScene);
+ } else ret = m_Scene->LoadFile(Filename);
+
+ if (SUCCEEDED(ret)) {
+ // invalidate references to the original scene
+ for (int i = 0; i < m_Objects.GetSize(); i++) {
+ m_Objects[i]->InvalidateCurrRegions();
+ m_Objects[i]->m_StickRegion = NULL;
+ }
+
+ m_Scene->LoadState();
+ }
+ if (FadeIn) Game->m_TransMgr->Start(TRANSITION_FADE_IN);
+ return ret;
+ } else return E_FAIL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::AddSentence(CAdSentence *Sentence) {
+ m_Sentences.Add(Sentence);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DisplaySentences(bool Frozen) {
+ for (int i = 0; i < m_Sentences.GetSize(); i++) {
+ if (Frozen && m_Sentences[i]->m_Freezable) continue;
+ else m_Sentences[i]->Display();
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::FinishSentences() {
+ for (int i = 0; i < m_Sentences.GetSize(); i++) {
+ if (m_Sentences[i]->CanSkip()) {
+ m_Sentences[i]->m_Duration = 0;
+ if (m_Sentences[i]->m_Sound) m_Sentences[i]->m_Sound->Stop();
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // ChangeScene
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "ChangeScene") == 0) {
+ Stack->CorrectParams(3);
+ char *Filename = Stack->Pop()->GetString();
+ CScValue *valFadeOut = Stack->Pop();
+ CScValue *valFadeIn = Stack->Pop();
+
+ bool TransOut = valFadeOut->IsNULL() ? true : valFadeOut->GetBool();
+ bool TransIn = valFadeIn->IsNULL() ? true : valFadeIn->GetBool();
+
+ ScheduleChangeScene(Filename, TransIn);
+ if (TransOut) m_TransMgr->Start(TRANSITION_FADE_OUT, true);
+ Stack->PushNULL();
+
+
+ //HRESULT ret = ChangeScene(Stack->Pop()->GetString());
+ //if(FAILED(ret)) Stack->PushBool(false);
+ //else Stack->PushBool(true);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadActor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadActor") == 0) {
+ Stack->CorrectParams(1);
+ CAdActor *act = new CAdActor(Game);
+ if (act && SUCCEEDED(act->LoadFile(Stack->Pop()->GetString()))) {
+ AddObject(act);
+ Stack->PushNative(act, true);
+ } else {
+ delete act;
+ act = NULL;
+ Stack->PushNULL();
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadEntity") == 0) {
+ Stack->CorrectParams(1);
+ CAdEntity *ent = new CAdEntity(Game);
+ if (ent && SUCCEEDED(ent->LoadFile(Stack->Pop()->GetString()))) {
+ AddObject(ent);
+ Stack->PushNative(ent, true);
+ } else {
+ delete ent;
+ ent = NULL;
+ Stack->PushNULL();
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // UnloadObject / UnloadActor / UnloadEntity / DeleteEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "UnloadObject") == 0 || strcmp(Name, "UnloadActor") == 0 || strcmp(Name, "UnloadEntity") == 0 || strcmp(Name, "DeleteEntity") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *val = Stack->Pop();
+ CAdObject *obj = (CAdObject *)val->GetNative();
+ RemoveObject(obj);
+ if (val->GetType() == VAL_VARIABLE_REF) val->SetNULL();
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CreateEntity") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdEntity *Ent = new CAdEntity(Game);
+ AddObject(Ent);
+ if (!Val->IsNULL()) Ent->SetName(Val->GetString());
+ Stack->PushNative(Ent, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CreateItem") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdItem *Item = new CAdItem(Game);
+ AddItem(Item);
+ if (!Val->IsNULL()) Item->SetName(Val->GetString());
+ Stack->PushNative(Item, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DeleteItem") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdItem *Item = NULL;
+ if (Val->IsNative()) Item = (CAdItem *)Val->GetNative();
+ else Item = GetItemByName(Val->GetString());
+
+ if (Item) {
+ DeleteItem(Item);
+ }
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // QueryItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "QueryItem") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdItem *Item = NULL;
+ if (Val->IsInt()) {
+ int Index = Val->GetInt();
+ if (Index >= 0 && Index < m_Items.GetSize()) Item = m_Items[Index];
+ } else {
+ Item = GetItemByName(Val->GetString());
+ }
+
+ if (Item) Stack->PushNative(Item, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddResponse/AddResponseOnce/AddResponseOnceGame
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddResponse") == 0 || strcmp(Name, "AddResponseOnce") == 0 || strcmp(Name, "AddResponseOnceGame") == 0) {
+ Stack->CorrectParams(6);
+ int id = Stack->Pop()->GetInt();
+ char *text = Stack->Pop()->GetString();
+ CScValue *val1 = Stack->Pop();
+ CScValue *val2 = Stack->Pop();
+ CScValue *val3 = Stack->Pop();
+ CScValue *val4 = Stack->Pop();
+
+ if (m_ResponseBox) {
+ CAdResponse *res = new CAdResponse(Game);
+ if (res) {
+ res->m_ID = id;
+ res->SetText(text);
+ m_StringTable->Expand(&res->m_Text);
+ if (!val1->IsNULL()) res->SetIcon(val1->GetString());
+ if (!val2->IsNULL()) res->SetIconHover(val2->GetString());
+ if (!val3->IsNULL()) res->SetIconPressed(val3->GetString());
+ if (!val4->IsNULL()) res->SetFont(val4->GetString());
+
+ if (strcmp(Name, "AddResponseOnce") == 0) res->m_ResponseType = RESPONSE_ONCE;
+ else if (strcmp(Name, "AddResponseOnceGame") == 0) res->m_ResponseType = RESPONSE_ONCE_GAME;
+
+ m_ResponseBox->m_Responses.Add(res);
+ }
+ } else {
+ Script->RuntimeError("Game.AddResponse: response box is not defined");
+ }
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ResetResponse
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ResetResponse") == 0) {
+ Stack->CorrectParams(1);
+ int ID = Stack->Pop()->GetInt(-1);
+ ResetResponse(ID);
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ClearResponses
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ClearResponses") == 0) {
+ Stack->CorrectParams(0);
+ m_ResponseBox->ClearResponses();
+ m_ResponseBox->ClearButtons();
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetResponse
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetResponse") == 0) {
+ Stack->CorrectParams(1);
+ bool AutoSelectLast = Stack->Pop()->GetBool();
+
+ if (m_ResponseBox) {
+ m_ResponseBox->WeedResponses();
+
+ if (m_ResponseBox->m_Responses.GetSize() == 0) {
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+
+ if (m_ResponseBox->m_Responses.GetSize() == 1 && AutoSelectLast) {
+ Stack->PushInt(m_ResponseBox->m_Responses[0]->m_ID);
+ m_ResponseBox->HandleResponse(m_ResponseBox->m_Responses[0]);
+ m_ResponseBox->ClearResponses();
+ return S_OK;
+ }
+
+ m_ResponseBox->CreateButtons();
+ m_ResponseBox->m_WaitingScript = Script;
+ Script->WaitForExclusive(m_ResponseBox);
+ m_State = GAME_SEMI_FROZEN;
+ m_StateEx = GAME_WAITING_RESPONSE;
+ } else {
+ Script->RuntimeError("Game.GetResponse: response box is not defined");
+ Stack->PushNULL();
+ }
+ return S_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetNumResponses
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetNumResponses") == 0) {
+ Stack->CorrectParams(0);
+ if (m_ResponseBox) {
+ m_ResponseBox->WeedResponses();
+ Stack->PushInt(m_ResponseBox->m_Responses.GetSize());
+ } else {
+ Script->RuntimeError("Game.GetNumResponses: response box is not defined");
+ Stack->PushNULL();
+ }
+ return S_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // StartDlgBranch
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StartDlgBranch") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+ char *BranchName = NULL;
+ bool DeleteName = false;
+ if (Val->IsNULL()) {
+ BranchName = new char[20];
+ sprintf(BranchName, "line%d", Script->m_CurrentLine);
+ DeleteName = true;
+ } else BranchName = Val->GetString();
+
+ StartDlgBranch(BranchName, Script->m_Filename == NULL ? "" : Script->m_Filename, Script->m_ThreadEvent == NULL ? "" : Script->m_ThreadEvent);
+ Stack->PushNULL();
+ if (DeleteName) delete[] BranchName;
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // EndDlgBranch
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "EndDlgBranch") == 0) {
+ Stack->CorrectParams(1);
+
+ char *BranchName = NULL;
+ CScValue *Val = Stack->Pop();
+ if (!Val->IsNULL()) BranchName = Val->GetString();
+ EndDlgBranch(BranchName, Script->m_Filename == NULL ? "" : Script->m_Filename, Script->m_ThreadEvent == NULL ? "" : Script->m_ThreadEvent);
+
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetCurrentDlgBranch
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetCurrentDlgBranch") == 0) {
+ Stack->CorrectParams(0);
+
+ if (m_DlgPendingBranches.GetSize() > 0) {
+ Stack->PushString(m_DlgPendingBranches[m_DlgPendingBranches.GetSize() - 1]);
+ } else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TakeItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TakeItem") == 0) {
+ return m_InvObject->ScCallMethod(Script, Stack, ThisStack, Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DropItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DropItem") == 0) {
+ return m_InvObject->ScCallMethod(Script, Stack, ThisStack, Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetItem") == 0) {
+ return m_InvObject->ScCallMethod(Script, Stack, ThisStack, Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HasItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "HasItem") == 0) {
+ return m_InvObject->ScCallMethod(Script, Stack, ThisStack, Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsItemTaken
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsItemTaken") == 0) {
+ Stack->CorrectParams(1);
+
+ CScValue *val = Stack->Pop();
+ if (!val->IsNULL()) {
+ for (int i = 0; i < m_Inventories.GetSize(); i++) {
+ CAdInventory *Inv = m_Inventories[i];
+
+ for (int j = 0; j < Inv->m_TakenItems.GetSize(); j++) {
+ if (val->GetNative() == Inv->m_TakenItems[j]) {
+ Stack->PushBool(true);
+ return S_OK;
+ } else if (scumm_stricmp(val->GetString(), Inv->m_TakenItems[j]->m_Name) == 0) {
+ Stack->PushBool(true);
+ return S_OK;
+ }
+ }
+ }
+ } else Script->RuntimeError("Game.IsItemTaken: item name expected");
+
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetInventoryWindow
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetInventoryWindow") == 0) {
+ Stack->CorrectParams(0);
+ if (m_InventoryBox && m_InventoryBox->m_Window)
+ Stack->PushNative(m_InventoryBox->m_Window, true);
+ else
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetResponsesWindow
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetResponsesWindow") == 0 || strcmp(Name, "GetResponseWindow") == 0) {
+ Stack->CorrectParams(0);
+ if (m_ResponseBox && m_ResponseBox->m_Window)
+ Stack->PushNative(m_ResponseBox->m_Window, true);
+ else
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadResponseBox
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadResponseBox") == 0) {
+ Stack->CorrectParams(1);
+ char *Filename = Stack->Pop()->GetString();
+
+ Game->UnregisterObject(m_ResponseBox);
+ m_ResponseBox = new CAdResponseBox(Game);
+ if (m_ResponseBox && !FAILED(m_ResponseBox->LoadFile(Filename))) {
+ RegisterObject(m_ResponseBox);
+ Stack->PushBool(true);
+ } else {
+ SAFE_DELETE(m_ResponseBox);
+ Stack->PushBool(false);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadInventoryBox
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadInventoryBox") == 0) {
+ Stack->CorrectParams(1);
+ char *Filename = Stack->Pop()->GetString();
+
+ Game->UnregisterObject(m_InventoryBox);
+ m_InventoryBox = new CAdInventoryBox(Game);
+ if (m_InventoryBox && !FAILED(m_InventoryBox->LoadFile(Filename))) {
+ RegisterObject(m_InventoryBox);
+ Stack->PushBool(true);
+ } else {
+ delete m_InventoryBox;
+ m_InventoryBox = NULL;
+ Stack->PushBool(false);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadItems") == 0) {
+ Stack->CorrectParams(2);
+ char *Filename = Stack->Pop()->GetString();
+ bool Merge = Stack->Pop()->GetBool(false);
+
+ HRESULT Ret = LoadItemsFile(Filename, Merge);
+ Stack->PushBool(SUCCEEDED(Ret));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddSpeechDir
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddSpeechDir") == 0) {
+ Stack->CorrectParams(1);
+ char *Dir = Stack->Pop()->GetString();
+ Stack->PushBool(SUCCEEDED(AddSpeechDir(Dir)));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // RemoveSpeechDir
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "RemoveSpeechDir") == 0) {
+ Stack->CorrectParams(1);
+ char *Dir = Stack->Pop()->GetString();
+ Stack->PushBool(SUCCEEDED(RemoveSpeechDir(Dir)));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetSceneViewport
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SetSceneViewport") == 0) {
+ Stack->CorrectParams(4);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+ int Width = Stack->Pop()->GetInt();
+ int Height = Stack->Pop()->GetInt();
+
+ if (Width <= 0) Width = m_Renderer->m_Width;
+ if (Height <= 0) Height = m_Renderer->m_Height;
+
+ if (!m_SceneViewport) m_SceneViewport = new CBViewport(Game);
+ if (m_SceneViewport) m_SceneViewport->SetRect(X, Y, X + Width, Y + Height);
+
+ Stack->PushBool(true);
+
+ return S_OK;
+ }
+
+
+ else return CBGame::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdGame::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("game");
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Scene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scene") == 0) {
+ if (m_Scene) m_ScValue->SetNative(m_Scene, true);
+ else m_ScValue->SetNULL();
+
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // SelectedItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SelectedItem") == 0) {
+ //if(m_SelectedItem) m_ScValue->SetString(m_SelectedItem->m_Name);
+ if (m_SelectedItem) m_ScValue->SetNative(m_SelectedItem, true);
+ else m_ScValue->SetNULL();
+
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // NumItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumItems") == 0) {
+ return m_InvObject->ScGetProperty(Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SmartItemCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SmartItemCursor") == 0) {
+ m_ScValue->SetBool(m_SmartItemCursor);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryVisible
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryVisible") == 0) {
+ m_ScValue->SetBool(m_InventoryBox && m_InventoryBox->m_Visible);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryScrollOffset
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryScrollOffset") == 0) {
+ if (m_InventoryBox) m_ScValue->SetInt(m_InventoryBox->m_ScrollOffset);
+ else m_ScValue->SetInt(0);
+
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ResponsesVisible (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ResponsesVisible") == 0) {
+ m_ScValue->SetBool(m_StateEx == GAME_WAITING_RESPONSE);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PrevScene / PreviousScene (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PrevScene") == 0 || strcmp(Name, "PreviousScene") == 0) {
+ if (!m_PrevSceneName) m_ScValue->SetString("");
+ else m_ScValue->SetString(m_PrevSceneName);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PrevSceneFilename / PreviousSceneFilename (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PrevSceneFilename") == 0 || strcmp(Name, "PreviousSceneFilename") == 0) {
+ if (!m_PrevSceneFilename) m_ScValue->SetString("");
+ else m_ScValue->SetString(m_PrevSceneFilename);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LastResponse (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LastResponse") == 0) {
+ if (!m_ResponseBox || !m_ResponseBox->m_LastResponseText) m_ScValue->SetString("");
+ else m_ScValue->SetString(m_ResponseBox->m_LastResponseText);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LastResponseOrig (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LastResponseOrig") == 0) {
+ if (!m_ResponseBox || !m_ResponseBox->m_LastResponseTextOrig) m_ScValue->SetString("");
+ else m_ScValue->SetString(m_ResponseBox->m_LastResponseTextOrig);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryObject") == 0) {
+ if (m_InventoryOwner == m_InvObject) m_ScValue->SetNative(this, true);
+ else m_ScValue->SetNative(m_InventoryOwner, true);
+
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TotalNumItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TotalNumItems") == 0) {
+ m_ScValue->SetInt(m_Items.GetSize());
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TalkSkipButton
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TalkSkipButton") == 0) {
+ m_ScValue->SetInt(m_TalkSkipButton);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ChangingScene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ChangingScene") == 0) {
+ m_ScValue->SetBool(m_ScheduledScene != NULL);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StartupScene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StartupScene") == 0) {
+ if (!m_StartupScene) m_ScValue->SetNULL();
+ else m_ScValue->SetString(m_StartupScene);
+ return m_ScValue;
+ }
+
+ else return CBGame::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ScSetProperty(char *Name, CScValue *Value) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // SelectedItem
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SelectedItem") == 0) {
+ if (Value->IsNULL()) m_SelectedItem = NULL;
+ else {
+ if (Value->IsNative()) {
+ m_SelectedItem = NULL;
+ for (int i = 0; i < m_Items.GetSize(); i++) {
+ if (m_Items[i] == Value->GetNative()) {
+ m_SelectedItem = (CAdItem *)Value->GetNative();
+ break;
+ }
+ }
+ } else {
+ // try to get by name
+ m_SelectedItem = GetItemByName(Value->GetString());
+ }
+ }
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SmartItemCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SmartItemCursor") == 0) {
+ m_SmartItemCursor = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryVisible
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryVisible") == 0) {
+ if (m_InventoryBox) m_InventoryBox->m_Visible = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryObject") == 0) {
+ if (m_InventoryOwner && m_InventoryBox) m_InventoryOwner->GetInventory()->m_ScrollOffset = m_InventoryBox->m_ScrollOffset;
+
+ if (Value->IsNULL()) m_InventoryOwner = m_InvObject;
+ else {
+ CBObject *Obj = (CBObject *)Value->GetNative();
+ if (Obj == this) m_InventoryOwner = m_InvObject;
+ else if (Game->ValidObject(Obj)) m_InventoryOwner = (CAdObject *)Obj;
+ }
+
+ if (m_InventoryOwner && m_InventoryBox) m_InventoryBox->m_ScrollOffset = m_InventoryOwner->GetInventory()->m_ScrollOffset;
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryScrollOffset
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryScrollOffset") == 0) {
+ if (m_InventoryBox) m_InventoryBox->m_ScrollOffset = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TalkSkipButton
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TalkSkipButton") == 0) {
+ int Val = Value->GetInt();
+ if (Val < 0) Val = 0;
+ if (Val > TALK_SKIP_NONE) Val = TALK_SKIP_NONE;
+ m_TalkSkipButton = (TTalkSkipButton)Val;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StartupScene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StartupScene") == 0) {
+ if (Value == NULL) {
+ delete[] m_StartupScene;
+ m_StartupScene = NULL;
+ } else CBUtils::SetString(&m_StartupScene, Value->GetString());
+
+ return S_OK;
+ }
+
+ else return CBGame::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::PublishNatives() {
+ if (!m_ScEngine || !m_ScEngine->m_CompilerAvailable) return;
+
+ CBGame::PublishNatives();
+
+ m_ScEngine->ExtDefineFunction("Actor");
+ m_ScEngine->ExtDefineFunction("Entity");
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ExternalCall(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ CScValue *this_obj;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Actor
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Actor") == 0) {
+ Stack->CorrectParams(0);
+ this_obj = ThisStack->GetTop();
+
+ this_obj->SetNative(new CAdActor(Game));
+ Stack->PushNULL();
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Entity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Entity") == 0) {
+ Stack->CorrectParams(0);
+ this_obj = ThisStack->GetTop();
+
+ this_obj->SetNative(new CAdEntity(Game));
+ Stack->PushNULL();
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // call parent
+ else return CBGame::ExternalCall(Script, Stack, ThisStack, Name);
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ShowCursor() {
+ if (m_CursorHidden) return S_OK;
+
+ if (m_SelectedItem && Game->m_State == GAME_RUNNING && m_StateEx == GAME_NORMAL && m_Interactive) {
+ if (m_SelectedItem->m_CursorCombined) {
+ CBSprite *OrigLastCursor = m_LastCursor;
+ CBGame::ShowCursor();
+ m_LastCursor = OrigLastCursor;
+ }
+ if (m_ActiveObject && m_SelectedItem->m_CursorHover && m_ActiveObject->GetExtendedFlag("usable")) {
+ if (!m_SmartItemCursor || m_ActiveObject->CanHandleEvent(m_SelectedItem->m_Name))
+ return DrawCursor(m_SelectedItem->m_CursorHover);
+ else
+ return DrawCursor(m_SelectedItem->m_CursorNormal);
+ } else return DrawCursor(m_SelectedItem->m_CursorNormal);
+ } else return CBGame::ShowCursor();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::LoadFile(const char *Filename) {
+ byte *Buffer = m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdGame::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing GAME file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(GAME)
+TOKEN_DEF(AD_GAME)
+TOKEN_DEF(RESPONSE_BOX)
+TOKEN_DEF(INVENTORY_BOX)
+TOKEN_DEF(ITEMS)
+TOKEN_DEF(ITEM)
+TOKEN_DEF(TALK_SKIP_BUTTON)
+TOKEN_DEF(SCENE_VIEWPORT)
+TOKEN_DEF(ENTITY_CONTAINER)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF(STARTUP_SCENE)
+TOKEN_DEF(DEBUG_STARTUP_SCENE)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(GAME)
+ TOKEN_TABLE(AD_GAME)
+ TOKEN_TABLE(RESPONSE_BOX)
+ TOKEN_TABLE(INVENTORY_BOX)
+ TOKEN_TABLE(ITEMS)
+ TOKEN_TABLE(TALK_SKIP_BUTTON)
+ TOKEN_TABLE(SCENE_VIEWPORT)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE(STARTUP_SCENE)
+ TOKEN_TABLE(DEBUG_STARTUP_SCENE)
+ TOKEN_TABLE_END
+
+ byte *params;
+ byte *params2;
+ int cmd = 1;
+ CBParser parser(Game);
+
+ bool ItemFound = false, ItemsFound = false;
+
+ while (cmd > 0 && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_GAME:
+ if (FAILED(CBGame::LoadBuffer(params, false))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_AD_GAME:
+ while (cmd > 0 && (cmd = parser.GetCommand((char **)&params, commands, (char **)&params2)) > 0) {
+ switch (cmd) {
+ case TOKEN_RESPONSE_BOX:
+ delete m_ResponseBox;
+ m_ResponseBox = new CAdResponseBox(Game);
+ if (m_ResponseBox && !FAILED(m_ResponseBox->LoadFile((char *)params2)))
+ RegisterObject(m_ResponseBox);
+ else {
+ delete m_ResponseBox;
+ m_ResponseBox = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_INVENTORY_BOX:
+ delete m_InventoryBox;
+ m_InventoryBox = new CAdInventoryBox(Game);
+ if (m_InventoryBox && !FAILED(m_InventoryBox->LoadFile((char *)params2)))
+ RegisterObject(m_InventoryBox);
+ else {
+ delete m_InventoryBox;
+ m_InventoryBox = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_ITEMS:
+ ItemsFound = true;
+ CBUtils::SetString(&m_ItemsFile, (char *)params2);
+ if (FAILED(LoadItemsFile(m_ItemsFile))) {
+ delete[] m_ItemsFile;
+ m_ItemsFile = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_TALK_SKIP_BUTTON:
+ if (scumm_stricmp((char *)params2, "right") == 0) m_TalkSkipButton = TALK_SKIP_RIGHT;
+ else if (scumm_stricmp((char *)params2, "both") == 0) m_TalkSkipButton = TALK_SKIP_BOTH;
+ else m_TalkSkipButton = TALK_SKIP_LEFT;
+ break;
+
+ case TOKEN_SCENE_VIEWPORT: {
+ RECT rc;
+ parser.ScanStr((char *)params2, "%d,%d,%d,%d", &rc.left, &rc.top, &rc.right, &rc.bottom);
+ if (!m_SceneViewport) m_SceneViewport = new CBViewport(Game);
+ if (m_SceneViewport) m_SceneViewport->SetRect(rc.left, rc.top, rc.right, rc.bottom);
+ }
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params2, false);
+ break;
+
+ case TOKEN_STARTUP_SCENE:
+ CBUtils::SetString(&m_StartupScene, (char *)params2);
+ break;
+
+ case TOKEN_DEBUG_STARTUP_SCENE:
+ CBUtils::SetString(&m_DebugStartupScene, (char *)params2);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in GAME definition");
+ return E_FAIL;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading GAME definition");
+ return E_FAIL;
+ }
+
+ if (ItemFound && !ItemsFound) {
+ Game->LOG(0, "**Warning** Please put the items definition to a separate file.");
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::Persist(CBPersistMgr *PersistMgr) {
+ if (!PersistMgr->m_Saving) Cleanup();
+ CBGame::Persist(PersistMgr);
+
+ m_DlgPendingBranches.Persist(PersistMgr);
+
+ m_Inventories.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_InventoryBox));
+
+ m_Objects.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_PrevSceneName));
+ PersistMgr->Transfer(TMEMBER(m_PrevSceneFilename));
+
+ PersistMgr->Transfer(TMEMBER(m_ResponseBox));
+ m_ResponsesBranch.Persist(PersistMgr);
+ m_ResponsesGame.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_Scene));
+ m_SceneStates.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_ScheduledFadeIn));
+ PersistMgr->Transfer(TMEMBER(m_ScheduledScene));
+ PersistMgr->Transfer(TMEMBER(m_SelectedItem));
+ PersistMgr->Transfer(TMEMBER_INT(m_TalkSkipButton));
+
+ m_Sentences.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_SceneViewport));
+ PersistMgr->Transfer(TMEMBER_INT(m_StateEx));
+ PersistMgr->Transfer(TMEMBER(m_InitialScene));
+ PersistMgr->Transfer(TMEMBER(m_DebugStartupScene));
+
+ PersistMgr->Transfer(TMEMBER(m_InvObject));
+ PersistMgr->Transfer(TMEMBER(m_InventoryOwner));
+ PersistMgr->Transfer(TMEMBER(m_TempDisableSaveState));
+ m_Items.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_ItemsFile));
+
+ m_SpeechDirs.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_SmartItemCursor));
+
+ if (!PersistMgr->m_Saving) m_InitialScene = false;
+
+ PersistMgr->Transfer(TMEMBER(m_StartupScene));
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::LoadGame(char *Filename) {
+ HRESULT ret = CBGame::LoadGame(Filename);
+ if (SUCCEEDED(ret)) CSysClassRegistry::GetInstance()->EnumInstances(AfterLoadRegion, "CAdRegion", NULL);
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::InitAfterLoad() {
+ CBGame::InitAfterLoad();
+ CSysClassRegistry::GetInstance()->EnumInstances(AfterLoadScene, "CAdScene", NULL);
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::AfterLoadScene(void *Scene, void *Data) {
+ ((CAdScene *)Scene)->AfterLoad();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::SetPrevSceneName(char *Name) {
+ delete[] m_PrevSceneName;
+ m_PrevSceneName = NULL;
+ if (Name) {
+ m_PrevSceneName = new char[strlen(Name) + 1];
+ if (m_PrevSceneName) strcpy(m_PrevSceneName, Name);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::SetPrevSceneFilename(char *Name) {
+ delete[] m_PrevSceneFilename;
+ m_PrevSceneFilename = NULL;
+ if (Name) {
+ m_PrevSceneFilename = new char[strlen(Name) + 1];
+ if (m_PrevSceneFilename) strcpy(m_PrevSceneFilename, Name);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ScheduleChangeScene(char *Filename, bool FadeIn) {
+ delete[] m_ScheduledScene;
+ m_ScheduledScene = NULL;
+
+ if (m_Scene && !m_Scene->m_Initialized) return ChangeScene(Filename, FadeIn);
+ else {
+ m_ScheduledScene = new char [strlen(Filename) + 1];
+ strcpy(m_ScheduledScene, Filename);
+
+ m_ScheduledFadeIn = FadeIn;
+
+ return S_OK;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::GetVersion(byte *VerMajor, byte *VerMinor, byte *ExtMajor, byte *ExtMinor) {
+ CBGame::GetVersion(VerMajor, VerMinor, NULL, NULL);
+
+ if (ExtMajor) *ExtMajor = 0;
+ if (ExtMinor) *ExtMinor = 0;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::LoadItemsFile(char *Filename, bool Merge) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdGame::LoadItemsFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ //m_Filename = new char [strlen(Filename)+1];
+ //strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadItemsBuffer(Buffer, Merge))) Game->LOG(0, "Error parsing ITEMS file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::LoadItemsBuffer(byte *Buffer, bool Merge) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ITEM)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (!Merge) {
+ while (m_Items.GetSize() > 0) DeleteItem(m_Items[0]);
+ }
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_ITEM: {
+ CAdItem *item = new CAdItem(Game);
+ if (item && !FAILED(item->LoadBuffer(params, false))) {
+ // delete item with the same name, if exists
+ if (Merge) {
+ CAdItem *PrevItem = GetItemByName(item->m_Name);
+ if (PrevItem) DeleteItem(PrevItem);
+ }
+ AddItem(item);
+ } else {
+ delete item;
+ item = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ }
+ break;
+ }
+ }
+
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in ITEMS definition");
+ return E_FAIL;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading ITEMS definition");
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneState *CAdGame::GetSceneState(char *Filename, bool Saving) {
+ char *FilenameCor = new char[strlen(Filename) + 1];
+ strcpy(FilenameCor, Filename);
+ for (int i = 0; i < strlen(FilenameCor); i++) {
+ if (FilenameCor[i] == '/') FilenameCor[i] = '\\';
+ }
+
+ for (int i = 0; i < m_SceneStates.GetSize(); i++) {
+ if (scumm_stricmp(m_SceneStates[i]->m_Filename, FilenameCor) == 0) {
+ delete [] FilenameCor;
+ return m_SceneStates[i];
+ }
+ }
+
+ if (Saving) {
+ CAdSceneState *ret = new CAdSceneState(Game);
+ ret->SetFilename(FilenameCor);
+
+ m_SceneStates.Add(ret);
+
+ delete [] FilenameCor;
+ return ret;
+ } else {
+ delete [] FilenameCor;
+ return NULL;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::WindowLoadHook(CUIWindow *Win, char **Buffer, char **params) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ENTITY_CONTAINER)
+ TOKEN_TABLE_END
+
+ int cmd = PARSERR_GENERIC;
+ CBParser parser(Game);
+
+ cmd = parser.GetCommand(Buffer, commands, params);
+ switch (cmd) {
+ case TOKEN_ENTITY_CONTAINER: {
+ CUIEntity *ent = new CUIEntity(Game);
+ if (!ent || FAILED(ent->LoadBuffer((byte *)*params, false))) {
+ delete ent;
+ ent = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ ent->m_Parent = Win;
+ Win->m_Widgets.Add(ent);
+ }
+ }
+ break;
+ }
+
+ if (cmd == PARSERR_TOKENNOTFOUND || cmd == PARSERR_GENERIC) {
+ return E_FAIL;
+ }
+
+ return S_OK;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::WindowScriptMethodHook(CUIWindow *Win, CScScript *Script, CScStack *Stack, char *Name) {
+ if (strcmp(Name, "CreateEntityContainer") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CUIEntity *Ent = new CUIEntity(Game);
+ if (!Val->IsNULL()) Ent->SetName(Val->GetString());
+ Stack->PushNative(Ent, true);
+
+ Ent->m_Parent = Win;
+ Win->m_Widgets.Add(Ent);
+
+ return S_OK;
+ } else return E_FAIL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::StartDlgBranch(const char *BranchName, const char *ScriptName, const char *EventName) {
+ char *Name = new char[strlen(BranchName) + 1 + strlen(ScriptName) + 1 + strlen(EventName) + 1];
+ if (Name) {
+ sprintf(Name, "%s.%s.%s", BranchName, ScriptName, EventName);
+ m_DlgPendingBranches.Add(Name);
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::EndDlgBranch(const char *BranchName, const char *ScriptName, const char *EventName) {
+ char *Name = NULL;
+ bool DeleteName = false;
+ if (BranchName == NULL && m_DlgPendingBranches.GetSize() > 0) {
+ Name = m_DlgPendingBranches[m_DlgPendingBranches.GetSize() - 1];
+ } else {
+ if (BranchName != NULL) {
+ Name = new char[strlen(BranchName) + 1 + strlen(ScriptName) + 1 + strlen(EventName) + 1];
+ if (Name) {
+ sprintf(Name, "%s.%s.%s", BranchName, ScriptName, EventName);
+ DeleteName = true;
+ }
+ }
+ }
+
+ if (Name == NULL) return S_OK;
+
+
+ int StartIndex = -1;
+ int i;
+ for (i = m_DlgPendingBranches.GetSize() - 1; i >= 0; i--) {
+ if (scumm_stricmp(Name, m_DlgPendingBranches[i]) == 0) {
+ StartIndex = i;
+ break;
+ }
+ }
+ if (StartIndex >= 0) {
+ for (i = StartIndex; i < m_DlgPendingBranches.GetSize(); i++) {
+ //ClearBranchResponses(m_DlgPendingBranches[i]);
+ delete [] m_DlgPendingBranches[i];
+ m_DlgPendingBranches[i] = NULL;
+ }
+ m_DlgPendingBranches.RemoveAt(StartIndex, m_DlgPendingBranches.GetSize() - StartIndex);
+ }
+
+ // dialogue is over, forget selected responses
+ if (m_DlgPendingBranches.GetSize() == 0) {
+ for (int i = 0; i < m_ResponsesBranch.GetSize(); i++) delete m_ResponsesBranch[i];
+ m_ResponsesBranch.RemoveAll();
+ }
+
+ if (DeleteName) delete [] Name;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ClearBranchResponses(char *Name) {
+ for (int i = 0; i < m_ResponsesBranch.GetSize(); i++) {
+ if (scumm_stricmp(Name, m_ResponsesBranch[i]->m_Context) == 0) {
+ delete m_ResponsesBranch[i];
+ m_ResponsesBranch.RemoveAt(i);
+ i--;
+ }
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddBranchResponse(int ID) {
+ if (BranchResponseUsed(ID)) return S_OK;
+ CAdResponseContext *r = new CAdResponseContext(Game);
+ r->m_ID = ID;
+ r->SetContext(m_DlgPendingBranches.GetSize() > 0 ? m_DlgPendingBranches[m_DlgPendingBranches.GetSize() - 1] : NULL);
+ m_ResponsesBranch.Add(r);
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::BranchResponseUsed(int ID) {
+ char *Context = m_DlgPendingBranches.GetSize() > 0 ? m_DlgPendingBranches[m_DlgPendingBranches.GetSize() - 1] : NULL;
+ for (int i = 0; i < m_ResponsesBranch.GetSize(); i++) {
+ if (m_ResponsesBranch[i]->m_ID == ID) {
+ if ((Context == NULL && m_ResponsesBranch[i]->m_Context == NULL) || scumm_stricmp(Context, m_ResponsesBranch[i]->m_Context) == 0) return true;
+ }
+ }
+ return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddGameResponse(int ID) {
+ if (GameResponseUsed(ID)) return S_OK;
+ CAdResponseContext *r = new CAdResponseContext(Game);
+ r->m_ID = ID;
+ r->SetContext(m_DlgPendingBranches.GetSize() > 0 ? m_DlgPendingBranches[m_DlgPendingBranches.GetSize() - 1] : NULL);
+ m_ResponsesGame.Add(r);
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::GameResponseUsed(int ID) {
+ char *Context = m_DlgPendingBranches.GetSize() > 0 ? m_DlgPendingBranches[m_DlgPendingBranches.GetSize() - 1] : NULL;
+ for (int i = 0; i < m_ResponsesGame.GetSize(); i++) {
+ CAdResponseContext *RespContext = m_ResponsesGame[i];
+ if (RespContext->m_ID == ID) {
+ if ((Context == NULL && RespContext->m_Context == NULL) || ((Context != NULL && RespContext->m_Context != NULL) && scumm_stricmp(Context, RespContext->m_Context) == 0)) return true;
+ }
+ }
+ return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ResetResponse(int ID) {
+ char *Context = m_DlgPendingBranches.GetSize() > 0 ? m_DlgPendingBranches[m_DlgPendingBranches.GetSize() - 1] : NULL;
+
+ int i;
+
+ for (i = 0; i < m_ResponsesGame.GetSize(); i++) {
+ if (m_ResponsesGame[i]->m_ID == ID) {
+ if ((Context == NULL && m_ResponsesGame[i]->m_Context == NULL) || scumm_stricmp(Context, m_ResponsesGame[i]->m_Context) == 0) {
+ delete m_ResponsesGame[i];
+ m_ResponsesGame.RemoveAt(i);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < m_ResponsesBranch.GetSize(); i++) {
+ if (m_ResponsesBranch[i]->m_ID == ID) {
+ if ((Context == NULL && m_ResponsesBranch[i]->m_Context == NULL) || scumm_stricmp(Context, m_ResponsesBranch[i]->m_Context) == 0) {
+ delete m_ResponsesBranch[i];
+ m_ResponsesBranch.RemoveAt(i);
+ break;
+ }
+ }
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DisplayContent(bool Update, bool DisplayAll) {
+ // init
+ if (Update) InitLoop();
+
+ // fill black
+ m_Renderer->Fill(0, 0, 0);
+ if (!m_EditorMode) m_Renderer->SetScreenViewport();
+
+ // process scripts
+ if (Update) m_ScEngine->Tick();
+
+ POINT p;
+ GetMousePos(&p);
+
+ m_Scene->Update();
+ m_Scene->Display();
+
+
+ // display in-game windows
+ DisplayWindows(true);
+ if (m_InventoryBox) m_InventoryBox->Display();
+ if (m_StateEx == GAME_WAITING_RESPONSE) m_ResponseBox->Display();
+ if (m_IndicatorDisplay) DisplayIndicator();
+
+
+ if (Update || DisplayAll) {
+ // display normal windows
+ DisplayWindows(false);
+
+ SetActiveObject(Game->m_Renderer->GetObjectAt(p.x, p.y));
+
+ // textual info
+ DisplaySentences(m_State == GAME_FROZEN);
+
+ ShowCursor();
+
+ if (m_Fader) m_Fader->Display();
+ m_TransMgr->Update();
+ }
+
+
+ if (m_LoadingIcon) {
+ m_LoadingIcon->Display(m_LoadingIconX, m_LoadingIconY);
+ if (!m_LoadingIconPersistent) {
+ delete m_LoadingIcon;
+ m_LoadingIcon = NULL;
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::RegisterInventory(CAdInventory *Inv) {
+ for (int i = 0; i < m_Inventories.GetSize(); i++) {
+ if (m_Inventories[i] == Inv) return S_OK;
+ }
+ RegisterObject(Inv);
+ m_Inventories.Add(Inv);
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::UnregisterInventory(CAdInventory *Inv) {
+ for (int i = 0; i < m_Inventories.GetSize(); i++) {
+ if (m_Inventories[i] == Inv) {
+ UnregisterObject(m_Inventories[i]);
+ m_Inventories.RemoveAt(i);
+ return S_OK;
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::IsItemTaken(char *ItemName) {
+ int i;
+
+ for (i = 0; i < m_Inventories.GetSize(); i++) {
+ CAdInventory *Inv = m_Inventories[i];
+
+ for (int j = 0; j < Inv->m_TakenItems.GetSize(); j++) {
+ if (scumm_stricmp(ItemName, Inv->m_TakenItems[j]->m_Name) == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CAdItem *CAdGame::GetItemByName(char *Name) {
+ for (int i = 0; i < m_Items.GetSize(); i++) {
+ if (scumm_stricmp(m_Items[i]->m_Name, Name) == 0) return m_Items[i];
+ }
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddItem(CAdItem *Item) {
+ m_Items.Add(Item);
+ return Game->RegisterObject(Item);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ResetContent() {
+ int i;
+
+ // clear pending dialogs
+ for (i = 0; i < m_DlgPendingBranches.GetSize(); i++) {
+ delete [] m_DlgPendingBranches[i];
+ }
+ m_DlgPendingBranches.RemoveAll();
+
+
+ // clear inventories
+ for (i = 0; i < m_Inventories.GetSize(); i++) {
+ m_Inventories[i]->m_TakenItems.RemoveAll();
+ }
+
+ // clear scene states
+ for (i = 0; i < m_SceneStates.GetSize(); i++) delete m_SceneStates[i];
+ m_SceneStates.RemoveAll();
+
+ // clear once responses
+ for (i = 0; i < m_ResponsesBranch.GetSize(); i++) delete m_ResponsesBranch[i];
+ m_ResponsesBranch.RemoveAll();
+
+ // clear once game responses
+ for (i = 0; i < m_ResponsesGame.GetSize(); i++) delete m_ResponsesGame[i];
+ m_ResponsesGame.RemoveAll();
+
+ // reload inventory items
+ if (m_ItemsFile) LoadItemsFile(m_ItemsFile);
+
+ m_TempDisableSaveState = true;
+
+ return CBGame::ResetContent();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DeleteItem(CAdItem *Item) {
+ if (!Item) return E_FAIL;
+
+ if (m_SelectedItem == Item) m_SelectedItem = NULL;
+ m_Scene->HandleItemAssociations(Item->m_Name, false);
+
+ // remove from all inventories
+ for (int i = 0; i < m_Inventories.GetSize(); i++) {
+ m_Inventories[i]->RemoveItem(Item);
+ }
+
+ // remove object
+ for (int i = 0; i < m_Items.GetSize(); i++) {
+ if (m_Items[i] == Item) {
+ UnregisterObject(m_Items[i]);
+ m_Items.RemoveAt(i);
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddSpeechDir(const char *Dir) {
+ if (!Dir || Dir[0] == '\0') return E_FAIL;
+
+ char *Temp = new char[strlen(Dir) + 2];
+ strcpy(Temp, Dir);
+ if (Temp[strlen(Temp) - 1] != '\\' && Temp[strlen(Temp) - 1] != '/')
+ strcat(Temp, "\\");
+
+ for (int i = 0; i < m_SpeechDirs.GetSize(); i++) {
+ if (scumm_stricmp(m_SpeechDirs[i], Temp) == 0) {
+ delete [] Temp;
+ return S_OK;
+ }
+ }
+ m_SpeechDirs.Add(Temp);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::RemoveSpeechDir(char *Dir) {
+ if (!Dir || Dir[0] == '\0') return E_FAIL;
+
+ char *Temp = new char[strlen(Dir) + 2];
+ strcpy(Temp, Dir);
+ if (Temp[strlen(Temp) - 1] != '\\' && Temp[strlen(Temp) - 1] != '/')
+ strcat(Temp, "\\");
+
+ bool Found = false;
+ for (int i = 0; i < m_SpeechDirs.GetSize(); i++) {
+ if (scumm_stricmp(m_SpeechDirs[i], Temp) == 0) {
+ delete [] m_SpeechDirs[i];
+ m_SpeechDirs.RemoveAt(i);
+ Found = true;
+ break;
+ }
+ }
+ delete [] Temp;
+
+ if (Found) return S_OK;
+ else return E_FAIL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdGame::FindSpeechFile(char *StringID) {
+ char *Ret = new char[MAX_PATH];
+
+ for (int i = 0; i < m_SpeechDirs.GetSize(); i++) {
+ sprintf(Ret, "%s%s.ogg", m_SpeechDirs[i], StringID);
+ CBFile *File = m_FileManager->OpenFile(Ret);
+ if (File) {
+ m_FileManager->CloseFile(File);
+ return Ret;
+ }
+
+ sprintf(Ret, "%s%s.wav", m_SpeechDirs[i], StringID);
+ File = m_FileManager->OpenFile(Ret);
+ if (File) {
+ m_FileManager->CloseFile(File);
+ return Ret;
+ }
+ }
+ delete [] Ret;
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::ValidMouse() {
+ POINT Pos;
+ CBPlatform::GetCursorPos(&Pos);
+
+ return m_Renderer->PointInViewport(&Pos);
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseLeftDown() {
+ if (!ValidMouse()) return S_OK;
+ if (m_State == GAME_RUNNING && !m_Interactive) {
+ if (m_TalkSkipButton == TALK_SKIP_LEFT || m_TalkSkipButton == TALK_SKIP_BOTH) {
+ FinishSentences();
+ }
+ return S_OK;
+ }
+
+ if (m_ActiveObject) m_ActiveObject->HandleMouse(MOUSE_CLICK, MOUSE_BUTTON_LEFT);
+
+ bool Handled = m_State == GAME_RUNNING && SUCCEEDED(ApplyEvent("LeftClick"));
+ if (!Handled) {
+ if (m_ActiveObject != NULL) {
+ m_ActiveObject->ApplyEvent("LeftClick");
+ } else if (m_State == GAME_RUNNING && m_Scene && m_Scene->PointInViewport(m_MousePos.x, m_MousePos.y)) {
+ m_Scene->ApplyEvent("LeftClick");
+ }
+ }
+
+ if (m_ActiveObject != NULL) Game->m_CapturedObject = Game->m_ActiveObject;
+ m_MouseLeftDown = true;
+ CBPlatform::SetCapture(m_Renderer->m_Window);
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseLeftUp() {
+ if (m_ActiveObject) m_ActiveObject->HandleMouse(MOUSE_RELEASE, MOUSE_BUTTON_LEFT);
+
+ CBPlatform::ReleaseCapture();
+ m_CapturedObject = NULL;
+ m_MouseLeftDown = false;
+
+ bool Handled = /*m_State==GAME_RUNNING &&*/ SUCCEEDED(ApplyEvent("LeftRelease"));
+ if (!Handled) {
+ if (m_ActiveObject != NULL) {
+ m_ActiveObject->ApplyEvent("LeftRelease");
+ } else if (m_State == GAME_RUNNING && m_Scene && m_Scene->PointInViewport(m_MousePos.x, m_MousePos.y)) {
+ m_Scene->ApplyEvent("LeftRelease");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseLeftDblClick() {
+ if (!ValidMouse()) return S_OK;
+
+ if (m_State == GAME_RUNNING && !m_Interactive) return S_OK;
+
+ if (m_ActiveObject) m_ActiveObject->HandleMouse(MOUSE_DBLCLICK, MOUSE_BUTTON_LEFT);
+
+ bool Handled = m_State == GAME_RUNNING && SUCCEEDED(ApplyEvent("LeftDoubleClick"));
+ if (!Handled) {
+ if (m_ActiveObject != NULL) {
+ m_ActiveObject->ApplyEvent("LeftDoubleClick");
+ } else if (m_State == GAME_RUNNING && m_Scene && m_Scene->PointInViewport(m_MousePos.x, m_MousePos.y)) {
+ m_Scene->ApplyEvent("LeftDoubleClick");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseRightDown() {
+ if (!ValidMouse()) return S_OK;
+ if (m_State == GAME_RUNNING && !m_Interactive) {
+ if (m_TalkSkipButton == TALK_SKIP_RIGHT || m_TalkSkipButton == TALK_SKIP_BOTH) {
+ FinishSentences();
+ }
+ return S_OK;
+ }
+
+ if ((m_State == GAME_RUNNING && !m_Interactive) || m_StateEx == GAME_WAITING_RESPONSE) return S_OK;
+
+ if (m_ActiveObject) m_ActiveObject->HandleMouse(MOUSE_CLICK, MOUSE_BUTTON_RIGHT);
+
+ bool Handled = m_State == GAME_RUNNING && SUCCEEDED(ApplyEvent("RightClick"));
+ if (!Handled) {
+ if (m_ActiveObject != NULL) {
+ m_ActiveObject->ApplyEvent("RightClick");
+ } else if (m_State == GAME_RUNNING && m_Scene && m_Scene->PointInViewport(m_MousePos.x, m_MousePos.y)) {
+ m_Scene->ApplyEvent("RightClick");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseRightUp() {
+ if (m_ActiveObject) m_ActiveObject->HandleMouse(MOUSE_RELEASE, MOUSE_BUTTON_RIGHT);
+
+ bool Handled = m_State == GAME_RUNNING && SUCCEEDED(ApplyEvent("RightRelease"));
+ if (!Handled) {
+ if (m_ActiveObject != NULL) {
+ m_ActiveObject->ApplyEvent("RightRelease");
+ } else if (m_State == GAME_RUNNING && m_Scene && m_Scene->PointInViewport(m_MousePos.x, m_MousePos.y)) {
+ m_Scene->ApplyEvent("RightRelease");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DisplayDebugInfo() {
+ char str[100];
+ if (Game->m_DEBUG_DebugMode) {
+ sprintf(str, "Mouse: %d, %d (scene: %d, %d)", m_MousePos.x, m_MousePos.y, m_MousePos.x + m_Scene->GetOffsetLeft(), m_MousePos.y + m_Scene->GetOffsetTop());
+ m_SystemFont->DrawText((byte *)str, 0, 90, m_Renderer->m_Width, TAL_RIGHT);
+
+ sprintf(str, "Scene: %s (prev: %s)", (m_Scene && m_Scene->m_Name) ? m_Scene->m_Name : "???", m_PrevSceneName ? m_PrevSceneName : "???");
+ m_SystemFont->DrawText((byte *)str, 0, 110, m_Renderer->m_Width, TAL_RIGHT);
+ }
+ return CBGame::DisplayDebugInfo();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnScriptShutdown(CScScript *Script) {
+ if (m_ResponseBox && m_ResponseBox->m_WaitingScript == Script)
+ m_ResponseBox->m_WaitingScript = NULL;
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdGame.h b/engines/wintermute/AdGame.h
new file mode 100644
index 0000000000..d879d9e045
--- /dev/null
+++ b/engines/wintermute/AdGame.h
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+#ifndef __WmeAdGame_H__
+#define __WmeAdGame_H__
+
+#include "AdTypes.h"
+#include "BGame.h"
+
+namespace WinterMute {
+class CAdItem;
+class CAdInventory;
+class CAdSceneState;
+class CAdScene;
+class CAdItem;
+class CAdObject;
+class CAdSentence;
+class CAdInventoryBox;
+class CAdResponseContext;
+class CAdResponseBox;
+class CAdGame : public CBGame {
+public:
+ virtual HRESULT OnScriptShutdown(CScScript *Script);
+
+ virtual HRESULT OnMouseLeftDown();
+ virtual HRESULT OnMouseLeftUp();
+ virtual HRESULT OnMouseLeftDblClick();
+ virtual HRESULT OnMouseRightDown();
+ virtual HRESULT OnMouseRightUp();
+
+ virtual HRESULT DisplayDebugInfo();
+
+
+ virtual HRESULT InitAfterLoad();
+ static void AfterLoadScene(void *Scene, void *Data);
+
+ bool m_SmartItemCursor;
+
+ CBArray<char *, char *> m_SpeechDirs;
+ HRESULT AddSpeechDir(const char *Dir);
+ HRESULT RemoveSpeechDir(char *Dir);
+ char *FindSpeechFile(char *StringID);
+
+ HRESULT DeleteItem(CAdItem *Item);
+ char *m_ItemsFile;
+ bool m_TempDisableSaveState;
+ virtual HRESULT ResetContent();
+ HRESULT AddItem(CAdItem *Item);
+ CAdItem *GetItemByName(char *Name);
+ CBArray<CAdItem *, CAdItem *> m_Items;
+ CAdObject *m_InventoryOwner;
+ bool IsItemTaken(char *ItemName);
+ HRESULT RegisterInventory(CAdInventory *Inv);
+ HRESULT UnregisterInventory(CAdInventory *Inv);
+
+ CAdObject *m_InvObject;
+ CBArray<CAdInventory *, CAdInventory *> m_Inventories;
+ virtual HRESULT DisplayContent(bool Update = true, bool DisplayAll = false);
+ char *m_DebugStartupScene;
+ char *m_StartupScene;
+ bool m_InitialScene;
+ bool GameResponseUsed(int ID);
+ HRESULT AddGameResponse(int ID);
+ HRESULT ResetResponse(int ID);
+
+ bool BranchResponseUsed(int ID);
+ HRESULT AddBranchResponse(int ID);
+ HRESULT ClearBranchResponses(char *Name);
+ HRESULT StartDlgBranch(const char *BranchName, const char *ScriptName, const char *EventName);
+ HRESULT EndDlgBranch(const char *BranchName, const char *ScriptName, const char *EventName);
+ virtual HRESULT WindowLoadHook(CUIWindow *Win, char **Buf, char **Params);
+ virtual HRESULT WindowScriptMethodHook(CUIWindow *Win, CScScript *Script, CScStack *Stack, char *Name);
+
+ CAdSceneState *GetSceneState(char *Filename, bool Saving);
+ CBViewport *m_SceneViewport;
+ int m_TexItemLifeTime;
+ int m_TexWalkLifeTime;
+ int m_TexStandLifeTime;
+ int m_TexTalkLifeTime;
+
+ TTalkSkipButton m_TalkSkipButton;
+
+ virtual HRESULT GetVersion(byte *VerMajor, byte *VerMinor, byte *ExtMajor, byte *ExtMinor);
+ HRESULT ScheduleChangeScene(char *Filename, bool FadeIn);
+ char *m_ScheduledScene;
+ bool m_ScheduledFadeIn;
+ void SetPrevSceneName(char *Name);
+ void SetPrevSceneFilename(char *Name);
+ char *m_PrevSceneName;
+ char *m_PrevSceneFilename;
+ virtual HRESULT LoadGame(char *Filename);
+ CAdItem *m_SelectedItem;
+ HRESULT Cleanup();
+ DECLARE_PERSISTENT(CAdGame, CBGame)
+
+ void FinishSentences();
+ HRESULT ShowCursor();
+ TGameStateEx m_StateEx;
+ CAdResponseBox *m_ResponseBox;
+ CAdInventoryBox *m_InventoryBox;
+ HRESULT DisplaySentences(bool Frozen);
+ void AddSentence(CAdSentence *Sentence);
+ HRESULT ChangeScene(char *Filename, bool FadeIn);
+ HRESULT RemoveObject(CAdObject *Object);
+ HRESULT AddObject(CAdObject *Object);
+ CAdScene *m_Scene;
+ HRESULT InitLoop();
+ CAdGame();
+ virtual ~CAdGame();
+ CBArray<CAdObject *, CAdObject *> m_Objects;
+ CBArray<CAdSentence *, CAdSentence *> m_Sentences;
+
+ CBArray<CAdSceneState *, CAdSceneState *> m_SceneStates;
+ CBArray<char *, char *> m_DlgPendingBranches;
+
+ CBArray<CAdResponseContext *, CAdResponseContext *> m_ResponsesBranch;
+ CBArray<CAdResponseContext *, CAdResponseContext *> m_ResponsesGame;
+
+ virtual HRESULT LoadFile(const char *Filename);
+ virtual HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+
+ HRESULT LoadItemsFile(char *Filename, bool Merge = false);
+ HRESULT LoadItemsBuffer(byte *Buffer, bool Merge = false);
+
+
+ virtual void PublishNatives();
+ virtual HRESULT ExternalCall(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(char *Name);
+ virtual HRESULT ScSetProperty(char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name);
+ bool ValidMouse();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdInventory.cpp b/engines/wintermute/AdInventory.cpp
new file mode 100644
index 0000000000..6723c6fe70
--- /dev/null
+++ b/engines/wintermute/AdInventory.cpp
@@ -0,0 +1,119 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "AdInventory.h"
+#include "ADGame.h"
+#include "AdItem.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdInventory, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventory::CAdInventory(CBGame *inGame): CBObject(inGame) {
+ m_ScrollOffset = 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventory::~CAdInventory() {
+ m_TakenItems.RemoveAll(); // ref only
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventory::InsertItem(char *Name, char *InsertAfter) {
+ if (Name == NULL) return E_FAIL;
+
+ CAdItem *item = ((CAdGame *)Game)->GetItemByName(Name);
+ if (item == NULL) return E_FAIL;
+
+ int InsertIndex = -1;
+ for (int i = 0; i < m_TakenItems.GetSize(); i++) {
+ if (scumm_stricmp(m_TakenItems[i]->m_Name, Name) == 0) {
+ m_TakenItems.RemoveAt(i);
+ i--;
+ continue;
+ }
+ if (InsertAfter && scumm_stricmp(m_TakenItems[i]->m_Name, InsertAfter) == 0) InsertIndex = i + 1;
+ }
+
+
+ if (InsertIndex == -1) m_TakenItems.Add(item);
+ else m_TakenItems.InsertAt(InsertIndex, item);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventory::RemoveItem(char *Name) {
+ if (Name == NULL) return E_FAIL;
+
+ for (int i = 0; i < m_TakenItems.GetSize(); i++) {
+ if (scumm_stricmp(m_TakenItems[i]->m_Name, Name) == 0) {
+ if (((CAdGame *)Game)->m_SelectedItem == m_TakenItems[i])((CAdGame *)Game)->m_SelectedItem = NULL;
+ m_TakenItems.RemoveAt(i);
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventory::RemoveItem(CAdItem *Item) {
+ if (Item == NULL) return E_FAIL;
+
+ for (int i = 0; i < m_TakenItems.GetSize(); i++) {
+ if (m_TakenItems[i] == Item) {
+ if (((CAdGame *)Game)->m_SelectedItem == m_TakenItems[i])((CAdGame *)Game)->m_SelectedItem = NULL;
+ m_TakenItems.RemoveAt(i);
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventory::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ m_TakenItems.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_ScrollOffset));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdInventory.h b/engines/wintermute/AdInventory.h
new file mode 100644
index 0000000000..828c37e964
--- /dev/null
+++ b/engines/wintermute/AdInventory.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdInventory_H__
+#define __WmeAdInventory_H__
+
+#include "BObject.h"
+
+namespace WinterMute {
+
+class CAdItem;
+
+class CAdInventory : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdInventory, CBObject)
+ HRESULT RemoveItem(char *Name);
+ HRESULT RemoveItem(CAdItem *Item);
+ HRESULT InsertItem(char *Name, char *InsertAfter = NULL);
+ CAdInventory(CBGame *inGame);
+ virtual ~CAdInventory();
+ CBArray<CAdItem *, CAdItem *> m_TakenItems;
+ int m_ScrollOffset;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdInventoryBox.cpp b/engines/wintermute/AdInventoryBox.cpp
new file mode 100644
index 0000000000..afaa139a6a
--- /dev/null
+++ b/engines/wintermute/AdInventoryBox.cpp
@@ -0,0 +1,368 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+#include "dcgf.h"
+#include "AdInventoryBox.h"
+#include "AdInventory.h"
+#include "BParser.h"
+#include "UIButton.h"
+#include "UIWindow.h"
+#include "BDynBuffer.h"
+#include "BGame.h"
+#include "AdGame.h"
+#include "AdItem.h"
+#include "BViewport.h"
+#include "BFileManager.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+#include <cmath>
+
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdInventoryBox, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventoryBox::CAdInventoryBox(CBGame *inGame): CBObject(inGame) {
+ CBPlatform::SetRectEmpty(&m_ItemsArea);
+ m_ScrollOffset = 0;
+ m_Spacing = 0;
+ m_ItemWidth = m_ItemHeight = 50;
+ m_ScrollBy = 1;
+
+ m_Window = NULL;
+ m_CloseButton = NULL;
+
+ m_HideSelected = false;
+
+ m_Visible = false;
+ m_Exclusive = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventoryBox::~CAdInventoryBox() {
+ Game->UnregisterObject(m_Window);
+ m_Window = NULL;
+
+ SAFE_DELETE(m_CloseButton);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::Listen(CBScriptHolder *param1, uint32 param2) {
+ CUIObject *obj = (CUIObject *)param1;
+
+ switch (obj->m_Type) {
+ case UI_BUTTON:
+ if (scumm_stricmp(obj->m_Name, "close") == 0) {
+ m_Visible = false;
+ } else if (scumm_stricmp(obj->m_Name, "prev") == 0) {
+ m_ScrollOffset -= m_ScrollBy;
+ m_ScrollOffset = std::max(m_ScrollOffset, 0);
+ } else if (scumm_stricmp(obj->m_Name, "next") == 0) {
+ m_ScrollOffset += m_ScrollBy;
+ } else return CBObject::Listen(param1, param2);
+ break;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::Display() {
+ CAdGame *AdGame = (CAdGame *)Game;
+
+ if (!m_Visible) return S_OK;
+
+ int ItemsX, ItemsY;
+ ItemsX = floor((float)((m_ItemsArea.right - m_ItemsArea.left + m_Spacing) / (m_ItemWidth + m_Spacing)));
+ ItemsY = floor((float)((m_ItemsArea.bottom - m_ItemsArea.top + m_Spacing) / (m_ItemHeight + m_Spacing)));
+
+ if (m_Window) {
+ m_Window->EnableWidget("prev", m_ScrollOffset > 0);
+ m_Window->EnableWidget("next", m_ScrollOffset + ItemsX * ItemsY < AdGame->m_InventoryOwner->GetInventory()->m_TakenItems.GetSize());
+ }
+
+
+ if (m_CloseButton) {
+ m_CloseButton->m_PosX = m_CloseButton->m_PosY = 0;
+ m_CloseButton->m_Width = Game->m_Renderer->m_Width;
+ m_CloseButton->m_Height = Game->m_Renderer->m_Height;
+
+ m_CloseButton->Display();
+ }
+
+
+ // display window
+ RECT rect = m_ItemsArea;
+ if (m_Window) {
+ CBPlatform::OffsetRect(&rect, m_Window->m_PosX, m_Window->m_PosY);
+ m_Window->Display();
+ }
+
+ // display items
+ if (m_Window && m_Window->m_AlphaColor != 0) Game->m_Renderer->m_ForceAlphaColor = m_Window->m_AlphaColor;
+ int yyy = rect.top;
+ for (int j = 0; j < ItemsY; j++) {
+ int xxx = rect.left;
+ for (int i = 0; i < ItemsX; i++) {
+ int ItemIndex = m_ScrollOffset + j * ItemsX + i;
+ if (ItemIndex >= 0 && ItemIndex < AdGame->m_InventoryOwner->GetInventory()->m_TakenItems.GetSize()) {
+ CAdItem *item = AdGame->m_InventoryOwner->GetInventory()->m_TakenItems[ItemIndex];
+ if (item != ((CAdGame *)Game)->m_SelectedItem || !m_HideSelected) {
+ item->Update();
+ item->Display(xxx, yyy);
+ }
+ }
+
+ xxx += (m_ItemWidth + m_Spacing);
+ }
+ yyy += (m_ItemHeight + m_Spacing);
+ }
+ if (m_Window && m_Window->m_AlphaColor != 0) Game->m_Renderer->m_ForceAlphaColor = 0;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdInventoryBox::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing INVENTORY_BOX file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(INVENTORY_BOX)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(WINDOW)
+TOKEN_DEF(EXCLUSIVE)
+TOKEN_DEF(ALWAYS_VISIBLE)
+TOKEN_DEF(AREA)
+TOKEN_DEF(SPACING)
+TOKEN_DEF(ITEM_WIDTH)
+TOKEN_DEF(ITEM_HEIGHT)
+TOKEN_DEF(SCROLL_BY)
+TOKEN_DEF(NAME)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(HIDE_SELECTED)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(INVENTORY_BOX)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(WINDOW)
+ TOKEN_TABLE(EXCLUSIVE)
+ TOKEN_TABLE(ALWAYS_VISIBLE)
+ TOKEN_TABLE(AREA)
+ TOKEN_TABLE(SPACING)
+ TOKEN_TABLE(ITEM_WIDTH)
+ TOKEN_TABLE(ITEM_HEIGHT)
+ TOKEN_TABLE(SCROLL_BY)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(HIDE_SELECTED)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd = 2;
+ CBParser parser(Game);
+ bool always_visible = false;
+
+ m_Exclusive = false;
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_INVENTORY_BOX) {
+ Game->LOG(0, "'INVENTORY_BOX' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ while (cmd > 0 && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ SetCaption((char *)params);
+ break;
+
+ case TOKEN_WINDOW:
+ SAFE_DELETE(m_Window);
+ m_Window = new CUIWindow(Game);
+ if (!m_Window || FAILED(m_Window->LoadBuffer(params, false))) {
+ SAFE_DELETE(m_Window);
+ cmd = PARSERR_GENERIC;
+ } else Game->RegisterObject(m_Window);
+ break;
+
+ case TOKEN_AREA:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_ItemsArea.left, &m_ItemsArea.top, &m_ItemsArea.right, &m_ItemsArea.bottom);
+ break;
+
+ case TOKEN_EXCLUSIVE:
+ parser.ScanStr((char *)params, "%b", &m_Exclusive);
+ break;
+
+ case TOKEN_HIDE_SELECTED:
+ parser.ScanStr((char *)params, "%b", &m_HideSelected);
+ break;
+
+ case TOKEN_ALWAYS_VISIBLE:
+ parser.ScanStr((char *)params, "%b", &always_visible);
+ break;
+
+ case TOKEN_SPACING:
+ parser.ScanStr((char *)params, "%d", &m_Spacing);
+ break;
+
+ case TOKEN_ITEM_WIDTH:
+ parser.ScanStr((char *)params, "%d", &m_ItemWidth);
+ break;
+
+ case TOKEN_ITEM_HEIGHT:
+ parser.ScanStr((char *)params, "%d", &m_ItemHeight);
+ break;
+
+ case TOKEN_SCROLL_BY:
+ parser.ScanStr((char *)params, "%d", &m_ScrollBy);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in INVENTORY_BOX definition");
+ return E_FAIL;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading INVENTORY_BOX definition");
+ return E_FAIL;
+ }
+
+ if (m_Exclusive) {
+ SAFE_DELETE(m_CloseButton);
+ m_CloseButton = new CUIButton(Game);
+ if (m_CloseButton) {
+ m_CloseButton->SetName("close");
+ m_CloseButton->SetListener(this, m_CloseButton, 0);
+ m_CloseButton->m_Parent = m_Window;
+ }
+ }
+
+ m_Visible = always_visible;
+
+ if (m_Window) {
+ for (int i = 0; i < m_Window->m_Widgets.GetSize(); i++) {
+ if (!m_Window->m_Widgets[i]->m_ListenerObject)
+ m_Window->m_Widgets[i]->SetListener(this, m_Window->m_Widgets[i], 0);
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "INVENTORY_BOX\n");
+ Buffer->PutTextIndent(Indent, "{\n");
+
+ Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", m_Name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+
+ Buffer->PutTextIndent(Indent + 2, "AREA { %d, %d, %d, %d }\n", m_ItemsArea.left, m_ItemsArea.top, m_ItemsArea.right, m_ItemsArea.bottom);
+
+ Buffer->PutTextIndent(Indent + 2, "EXCLUSIVE=%s\n", m_Exclusive ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "HIDE_SELECTED=%s\n", m_HideSelected ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "ALWAYS_VISIBLE=%s\n", m_Visible ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "SPACING=%d\n", m_Spacing);
+ Buffer->PutTextIndent(Indent + 2, "ITEM_WIDTH=%d\n", m_ItemWidth);
+ Buffer->PutTextIndent(Indent + 2, "ITEM_HEIGHT=%d\n", m_ItemHeight);
+ Buffer->PutTextIndent(Indent + 2, "SCROLL_BY=%d\n", m_ScrollBy);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // window
+ if (m_Window) m_Window->SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // editor properties
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n");
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_CloseButton));
+ PersistMgr->Transfer(TMEMBER(m_HideSelected));
+ PersistMgr->Transfer(TMEMBER(m_ItemHeight));
+ PersistMgr->Transfer(TMEMBER(m_ItemsArea));
+ PersistMgr->Transfer(TMEMBER(m_ItemWidth));
+ PersistMgr->Transfer(TMEMBER(m_ScrollBy));
+ PersistMgr->Transfer(TMEMBER(m_ScrollOffset));
+ PersistMgr->Transfer(TMEMBER(m_Spacing));
+ PersistMgr->Transfer(TMEMBER(m_Visible));
+ PersistMgr->Transfer(TMEMBER(m_Window));
+ PersistMgr->Transfer(TMEMBER(m_Exclusive));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdInventoryBox.h b/engines/wintermute/AdInventoryBox.h
new file mode 100644
index 0000000000..94cb40dbf6
--- /dev/null
+++ b/engines/wintermute/AdInventoryBox.h
@@ -0,0 +1,63 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdInventoryBox_H__
+#define __WmeAdInventoryBox_H__
+
+#include "BObject.h"
+
+namespace WinterMute {
+class CUIButton;
+class CUIWindow;
+
+class CAdInventoryBox : public CBObject {
+public:
+ bool m_HideSelected;
+ DECLARE_PERSISTENT(CAdInventoryBox, CBObject)
+ bool m_Exclusive;
+ int m_ScrollBy;
+ int m_ItemHeight;
+ int m_ItemWidth;
+ bool m_Visible;
+ virtual HRESULT Display();
+ CUIButton *m_CloseButton;
+ int m_Spacing;
+ int m_ScrollOffset;
+ RECT m_ItemsArea;
+ HRESULT Listen(CBScriptHolder *param1, uint32 param2);
+ CUIWindow *m_Window;
+ CAdInventoryBox(CBGame *inGame);
+ virtual ~CAdInventoryBox();
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdItem.cpp b/engines/wintermute/AdItem.cpp
new file mode 100644
index 0000000000..5a2d4d7a58
--- /dev/null
+++ b/engines/wintermute/AdItem.cpp
@@ -0,0 +1,754 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdItem.h"
+#include "BParser.h"
+#include "ScValue.h"
+#include "BGame.h"
+#include "AdGame.h"
+#include "BSound.h"
+#include "BFontStorage.h"
+#include "BFont.h"
+#include "AdSentence.h"
+#include "ScScript.h"
+#include "ScStack.h"
+#include "BSprite.h"
+#include "BFileManager.h"
+#include "utils.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdItem, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdItem::CAdItem(CBGame *inGame): CAdTalkHolder(inGame) {
+ m_SpriteHover = NULL;
+ m_CursorNormal = m_CursorHover = NULL;
+
+ m_CursorCombined = true;
+ m_InInventory = false;
+
+ m_DisplayAmount = false;
+ m_Amount = 0;
+ m_AmountOffsetX = 0;
+ m_AmountOffsetY = 0;
+ m_AmountAlign = TAL_RIGHT;
+ m_AmountString = NULL;
+
+ m_State = STATE_READY;
+
+ m_Movable = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdItem::~CAdItem() {
+ delete m_SpriteHover;
+ delete m_CursorNormal;
+ delete m_CursorHover;
+ m_SpriteHover = NULL;
+ m_CursorNormal = NULL;
+ m_CursorHover = NULL;
+
+ delete[] m_AmountString;
+ m_AmountString = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdItem::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing ITEM file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(ITEM)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(CURSOR_HOVER)
+TOKEN_DEF(CURSOR_COMBINED)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(NAME)
+TOKEN_DEF(IMAGE_HOVER)
+TOKEN_DEF(IMAGE)
+TOKEN_DEF(EVENTS)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PROPERTY)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF(FONT)
+TOKEN_DEF(ALPHA_COLOR)
+TOKEN_DEF(ALPHA)
+TOKEN_DEF(TALK_SPECIAL)
+TOKEN_DEF(TALK)
+TOKEN_DEF(SPRITE_HOVER)
+TOKEN_DEF(SPRITE)
+TOKEN_DEF(DISPLAY_AMOUNT)
+TOKEN_DEF(AMOUNT_OFFSET_X)
+TOKEN_DEF(AMOUNT_OFFSET_Y)
+TOKEN_DEF(AMOUNT_ALIGN)
+TOKEN_DEF(AMOUNT_STRING)
+TOKEN_DEF(AMOUNT)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ITEM)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(CURSOR_HOVER)
+ TOKEN_TABLE(CURSOR_COMBINED)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(IMAGE_HOVER)
+ TOKEN_TABLE(IMAGE)
+ TOKEN_TABLE(EVENTS)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PROPERTY)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(ALPHA_COLOR)
+ TOKEN_TABLE(ALPHA)
+ TOKEN_TABLE(TALK_SPECIAL)
+ TOKEN_TABLE(TALK)
+ TOKEN_TABLE(SPRITE_HOVER)
+ TOKEN_TABLE(SPRITE)
+ TOKEN_TABLE(DISPLAY_AMOUNT)
+ TOKEN_TABLE(AMOUNT_OFFSET_X)
+ TOKEN_TABLE(AMOUNT_OFFSET_Y)
+ TOKEN_TABLE(AMOUNT_ALIGN)
+ TOKEN_TABLE(AMOUNT_STRING)
+ TOKEN_TABLE(AMOUNT)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd = 2;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_ITEM) {
+ Game->LOG(0, "'ITEM' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ int ar = 0, ag = 0, ab = 0, alpha = 255;
+ while (cmd > 0 && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_FONT:
+ SetFont((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ SetCaption((char *)params);
+ break;
+
+ case TOKEN_IMAGE:
+ case TOKEN_SPRITE:
+ delete m_Sprite;
+ m_Sprite = new CBSprite(Game, this);
+ if (!m_Sprite || FAILED(m_Sprite->LoadFile((char *)params, ((CAdGame *)Game)->m_TexItemLifeTime))) {
+ delete m_Sprite;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE_HOVER:
+ case TOKEN_SPRITE_HOVER:
+ delete m_SpriteHover;
+ m_SpriteHover = new CBSprite(Game, this);
+ if (!m_SpriteHover || FAILED(m_SpriteHover->LoadFile((char *)params, ((CAdGame *)Game)->m_TexItemLifeTime))) {
+ delete m_SpriteHover;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_AMOUNT:
+ parser.ScanStr((char *)params, "%d", &m_Amount);
+ break;
+
+ case TOKEN_DISPLAY_AMOUNT:
+ parser.ScanStr((char *)params, "%b", &m_DisplayAmount);
+ break;
+
+ case TOKEN_AMOUNT_OFFSET_X:
+ parser.ScanStr((char *)params, "%d", &m_AmountOffsetX);
+ break;
+
+ case TOKEN_AMOUNT_OFFSET_Y:
+ parser.ScanStr((char *)params, "%d", &m_AmountOffsetY);
+ break;
+
+ case TOKEN_AMOUNT_ALIGN:
+ if (scumm_stricmp((char *)params, "left") == 0) m_AmountAlign = TAL_LEFT;
+ else if (scumm_stricmp((char *)params, "right") == 0) m_AmountAlign = TAL_RIGHT;
+ else m_AmountAlign = TAL_CENTER;
+ break;
+
+ case TOKEN_AMOUNT_STRING:
+ CBUtils::SetString(&m_AmountString, (char *)params);
+ break;
+
+ case TOKEN_TALK: {
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, ((CAdGame *)Game)->m_TexTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else m_TalkSprites.Add(spr);
+ }
+ break;
+
+ case TOKEN_TALK_SPECIAL: {
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, ((CAdGame *)Game)->m_TexTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else m_TalkSpritesEx.Add(spr);
+ }
+ break;
+
+ case TOKEN_CURSOR:
+ delete m_CursorNormal;
+ m_CursorNormal = new CBSprite(Game);
+ if (!m_CursorNormal || FAILED(m_CursorNormal->LoadFile((char *)params, ((CAdGame *)Game)->m_TexItemLifeTime))) {
+ delete m_CursorNormal;
+ m_CursorNormal = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_CURSOR_HOVER:
+ delete m_CursorHover;
+ m_CursorHover = new CBSprite(Game);
+ if (!m_CursorHover || FAILED(m_CursorHover->LoadFile((char *)params, ((CAdGame *)Game)->m_TexItemLifeTime))) {
+ delete m_CursorHover;
+ m_CursorHover = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_CURSOR_COMBINED:
+ parser.ScanStr((char *)params, "%b", &m_CursorCombined);
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_ALPHA_COLOR:
+ parser.ScanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab);
+ break;
+
+ case TOKEN_ALPHA:
+ parser.ScanStr((char *)params, "%d", &alpha);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in ITEM definition");
+ return E_FAIL;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading ITEM definition");
+ return E_FAIL;
+ }
+
+ if (alpha != 0 && ar == 0 && ag == 0 && ab == 0) {
+ ar = ag = ab = 255;
+ }
+ m_AlphaColor = DRGBA(ar, ag, ab, alpha);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::Update() {
+ m_CurrentSprite = NULL;
+
+ if (m_State == STATE_READY && m_AnimSprite) {
+ delete m_AnimSprite;
+ m_AnimSprite = NULL;
+ }
+
+ // finished playing animation?
+ if (m_State == STATE_PLAYING_ANIM && m_AnimSprite != NULL && m_AnimSprite->m_Finished) {
+ m_State = STATE_READY;
+ m_CurrentSprite = m_AnimSprite;
+ }
+
+ if (m_Sentence && m_State != STATE_TALKING) m_Sentence->Finish();
+
+ // default: stand animation
+ if (!m_CurrentSprite) m_CurrentSprite = m_Sprite;
+
+ switch (m_State) {
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM:
+ m_CurrentSprite = m_AnimSprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_READY:
+ if (!m_AnimSprite) {
+ if (Game->m_ActiveObject == this && m_SpriteHover) m_CurrentSprite = m_SpriteHover;
+ else m_CurrentSprite = m_Sprite;
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TALKING: {
+ m_Sentence->Update();
+ if (m_Sentence->m_CurrentSprite) m_TempSprite2 = m_Sentence->m_CurrentSprite;
+
+ bool TimeIsUp = (m_Sentence->m_Sound && m_Sentence->m_SoundStarted && (!m_Sentence->m_Sound->IsPlaying() && !m_Sentence->m_Sound->IsPaused())) || (!m_Sentence->m_Sound && m_Sentence->m_Duration <= Game->m_Timer - m_Sentence->m_StartTime);
+ if (m_TempSprite2 == NULL || m_TempSprite2->m_Finished || (/*m_TempSprite2->m_Looping &&*/ TimeIsUp)) {
+ if (TimeIsUp) {
+ m_Sentence->Finish();
+ m_TempSprite2 = NULL;
+ m_State = STATE_READY;
+ } else {
+ m_TempSprite2 = GetTalkStance(m_Sentence->GetNextStance());
+ if (m_TempSprite2) {
+ m_TempSprite2->Reset();
+ m_CurrentSprite = m_TempSprite2;
+ }
+ ((CAdGame *)Game)->AddSentence(m_Sentence);
+ }
+ } else {
+ m_CurrentSprite = m_TempSprite2;
+ ((CAdGame *)Game)->AddSentence(m_Sentence);
+ }
+ }
+ break;
+ }
+ m_Ready = (m_State == STATE_READY);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::Display(int X, int Y) {
+ int Width = 0;
+ if (m_CurrentSprite) {
+ RECT rc;
+ m_CurrentSprite->GetBoundingRect(&rc, 0, 0);
+ Width = rc.right - rc.left;
+ }
+
+ m_PosX = X + Width / 2;
+ m_PosY = Y;
+
+ HRESULT ret;
+ if (m_CurrentSprite) ret = m_CurrentSprite->Draw(X, Y, this, 100, 100, m_AlphaColor);
+ else ret = S_OK;
+
+ if (m_DisplayAmount) {
+ int AmountX = X;
+ int AmountY = Y + m_AmountOffsetY;
+
+ if (m_AmountAlign == TAL_RIGHT) {
+ Width -= m_AmountOffsetX;
+ AmountX -= m_AmountOffsetX;
+ }
+ AmountX += m_AmountOffsetX;
+
+ CBFont *Font = m_Font ? m_Font : Game->m_SystemFont;
+ if (Font) {
+ if (m_AmountString) Font->DrawText((byte *)m_AmountString, AmountX, AmountY, Width, m_AmountAlign);
+ else {
+ char Str[256];
+ sprintf(Str, "%d", m_Amount);
+ Font->DrawText((byte *)Str, AmountX, AmountY, Width, m_AmountAlign);
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetHoverSprite
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetHoverSprite") == 0) {
+ Stack->CorrectParams(1);
+
+ bool SetCurrent = false;
+ if (m_CurrentSprite && m_CurrentSprite == m_SpriteHover) SetCurrent = true;
+
+ char *Filename = Stack->Pop()->GetString();
+
+ delete m_SpriteHover;
+ m_SpriteHover = NULL;
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ Stack->PushBool(false);
+ Script->RuntimeError("Item.SetHoverSprite failed for file '%s'", Filename);
+ } else {
+ m_SpriteHover = spr;
+ if (SetCurrent) m_CurrentSprite = m_SpriteHover;
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverSprite") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!m_SpriteHover || !m_SpriteHover->m_Filename) Stack->PushNULL();
+ else Stack->PushString(m_SpriteHover->m_Filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverSpriteObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverSpriteObject") == 0) {
+ Stack->CorrectParams(0);
+ if (!m_SpriteHover) Stack->PushNULL();
+ else Stack->PushNative(m_SpriteHover, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetNormalCursor
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetNormalCursor") == 0) {
+ Stack->CorrectParams(1);
+
+ char *Filename = Stack->Pop()->GetString();
+
+ delete m_CursorNormal;
+ m_CursorNormal = NULL;
+ CBSprite *spr = new CBSprite(Game);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ Stack->PushBool(false);
+ Script->RuntimeError("Item.SetNormalCursor failed for file '%s'", Filename);
+ } else {
+ m_CursorNormal = spr;
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetNormalCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetNormalCursor") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!m_CursorNormal || !m_CursorNormal->m_Filename) Stack->PushNULL();
+ else Stack->PushString(m_CursorNormal->m_Filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetNormalCursorObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetNormalCursorObject") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!m_CursorNormal) Stack->PushNULL();
+ else Stack->PushNative(m_CursorNormal, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetHoverCursor
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetHoverCursor") == 0) {
+ Stack->CorrectParams(1);
+
+ char *Filename = Stack->Pop()->GetString();
+
+ delete m_CursorHover;
+ m_CursorHover = NULL;
+ CBSprite *spr = new CBSprite(Game);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ Stack->PushBool(false);
+ Script->RuntimeError("Item.SetHoverCursor failed for file '%s'", Filename);
+ } else {
+ m_CursorHover = spr;
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverCursor") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!m_CursorHover || !m_CursorHover->m_Filename) Stack->PushNULL();
+ else Stack->PushString(m_CursorHover->m_Filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverCursorObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverCursorObject") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!m_CursorHover) Stack->PushNULL();
+ else Stack->PushNative(m_CursorHover, true);
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdItem::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("item");
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Name") == 0) {
+ m_ScValue->SetString(m_Name);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DisplayAmount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DisplayAmount") == 0) {
+ m_ScValue->SetBool(m_DisplayAmount);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Amount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Amount") == 0) {
+ m_ScValue->SetInt(m_Amount);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetX") == 0) {
+ m_ScValue->SetInt(m_AmountOffsetX);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetY") == 0) {
+ m_ScValue->SetInt(m_AmountOffsetY);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountAlign") == 0) {
+ m_ScValue->SetInt(m_AmountAlign);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountString
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountString") == 0) {
+ if (!m_AmountString) m_ScValue->SetNULL();
+ else m_ScValue->SetString(m_AmountString);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorCombined
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CursorCombined") == 0) {
+ m_ScValue->SetBool(m_CursorCombined);
+ return m_ScValue;
+ }
+
+ else return CAdTalkHolder::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::ScSetProperty(char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DisplayAmount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DisplayAmount") == 0) {
+ m_DisplayAmount = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Amount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Amount") == 0) {
+ m_Amount = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetX") == 0) {
+ m_AmountOffsetX = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetY") == 0) {
+ m_AmountOffsetY = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountAlign") == 0) {
+ m_AmountAlign = (TTextAlign)Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountString
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountString") == 0) {
+ if (Value->IsNULL()) SAFE_DELETE_ARRAY(m_AmountString);
+ else CBUtils::SetString(&m_AmountString, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorCombined
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CursorCombined") == 0) {
+ m_CursorCombined = Value->GetBool();
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdItem::ScToString() {
+ return "[item]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::Persist(CBPersistMgr *PersistMgr) {
+
+ CAdTalkHolder::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_CursorCombined));
+ PersistMgr->Transfer(TMEMBER(m_CursorHover));
+ PersistMgr->Transfer(TMEMBER(m_CursorNormal));
+ PersistMgr->Transfer(TMEMBER(m_SpriteHover));
+ PersistMgr->Transfer(TMEMBER(m_InInventory));
+ PersistMgr->Transfer(TMEMBER(m_DisplayAmount));
+ PersistMgr->Transfer(TMEMBER(m_Amount));
+ PersistMgr->Transfer(TMEMBER(m_AmountOffsetX));
+ PersistMgr->Transfer(TMEMBER(m_AmountOffsetY));
+ PersistMgr->Transfer(TMEMBER_INT(m_AmountAlign));
+ PersistMgr->Transfer(TMEMBER(m_AmountString));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdItem::GetExtendedFlag(char *FlagName) {
+ if (!FlagName) return false;
+ else if (strcmp(FlagName, "usable") == 0) return true;
+ else return CAdObject::GetExtendedFlag(FlagName);
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdItem.h b/engines/wintermute/AdItem.h
new file mode 100644
index 0000000000..8bb9cd46a0
--- /dev/null
+++ b/engines/wintermute/AdItem.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdItem_H__
+#define __WmeAdItem_H__
+
+
+#include "AdTalkHolder.h"
+
+namespace WinterMute {
+
+class CAdItem : public CAdTalkHolder {
+public:
+ bool m_DisplayAmount;
+ int m_Amount;
+ int m_AmountOffsetX;
+ int m_AmountOffsetY;
+ TTextAlign m_AmountAlign;
+ char *m_AmountString;
+
+
+ HRESULT Update();
+ DECLARE_PERSISTENT(CAdItem, CAdTalkHolder)
+ HRESULT Display(int X, int Y);
+ bool GetExtendedFlag(char *FlagName);
+ bool m_InInventory;
+ bool m_CursorCombined;
+ CBSprite *m_SpriteHover;
+ CBSprite *m_CursorNormal;
+ CBSprite *m_CursorHover;
+ CAdItem(CBGame *inGame);
+ virtual ~CAdItem();
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(char *Name);
+ virtual HRESULT ScSetProperty(char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name);
+ virtual char *ScToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdLayer.cpp b/engines/wintermute/AdLayer.cpp
new file mode 100644
index 0000000000..6fc53ede7e
--- /dev/null
+++ b/engines/wintermute/AdLayer.cpp
@@ -0,0 +1,535 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "BGame.h"
+#include "AdLayer.h"
+#include "AdSceneNode.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "ScValue.h"
+#include "ScScript.h"
+#include "ScStack.h"
+#include "BFileManager.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdLayer, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdLayer::CAdLayer(CBGame *inGame): CBObject(inGame) {
+ m_Main = false;
+ m_Width = m_Height = 0;
+ m_Active = true;
+ m_CloseUp = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdLayer::~CAdLayer() {
+ for (int i = 0; i < m_Nodes.GetSize(); i++)
+ delete m_Nodes[i];
+ m_Nodes.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdLayer::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing LAYER file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(LAYER)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(NAME)
+TOKEN_DEF(WIDTH)
+TOKEN_DEF(HEIGHT)
+TOKEN_DEF(MAIN)
+TOKEN_DEF(ENTITY)
+TOKEN_DEF(REGION)
+TOKEN_DEF(ACTIVE)
+TOKEN_DEF(EDITOR_SELECTED)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PROPERTY)
+TOKEN_DEF(CLOSE_UP)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(LAYER)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(WIDTH)
+ TOKEN_TABLE(HEIGHT)
+ TOKEN_TABLE(MAIN)
+ TOKEN_TABLE(ENTITY)
+ TOKEN_TABLE(REGION)
+ TOKEN_TABLE(ACTIVE)
+ TOKEN_TABLE(EDITOR_SELECTED)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PROPERTY)
+ TOKEN_TABLE(CLOSE_UP)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_LAYER) {
+ Game->LOG(0, "'LAYER' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ SetCaption((char *)params);
+ break;
+
+ case TOKEN_MAIN:
+ parser.ScanStr((char *)params, "%b", &m_Main);
+ break;
+
+ case TOKEN_CLOSE_UP:
+ parser.ScanStr((char *)params, "%b", &m_CloseUp);
+ break;
+
+ case TOKEN_WIDTH:
+ parser.ScanStr((char *)params, "%d", &m_Width);
+ break;
+
+ case TOKEN_HEIGHT:
+ parser.ScanStr((char *)params, "%d", &m_Height);
+ break;
+
+ case TOKEN_ACTIVE:
+ parser.ScanStr((char *)params, "%b", &m_Active);
+ break;
+
+ case TOKEN_REGION: {
+ CAdRegion *region = new CAdRegion(Game);
+ CAdSceneNode *node = new CAdSceneNode(Game);
+ if (!region || !node || FAILED(region->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ delete region;
+ delete node;
+ region = NULL;
+ node = NULL;
+ } else {
+ node->SetRegion(region);
+ m_Nodes.Add(node);
+ }
+ }
+ break;
+
+ case TOKEN_ENTITY: {
+ CAdEntity *entity = new CAdEntity(Game);
+ CAdSceneNode *node = new CAdSceneNode(Game);
+ if (entity) entity->m_Zoomable = false; // scene entites default to NOT zoom
+ if (!entity || !node || FAILED(entity->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ delete entity;
+ delete node;
+ entity = NULL;
+ node = NULL;
+ } else {
+ node->SetEntity(entity);
+ m_Nodes.Add(node);
+ }
+ }
+ break;
+
+ case TOKEN_EDITOR_SELECTED:
+ parser.ScanStr((char *)params, "%b", &m_EditorSelected);
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in LAYER definition");
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // GetNode
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "GetNode") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *val = Stack->Pop();
+ int node = -1;
+
+ if (val->m_Type == VAL_INT) node = val->GetInt();
+ else { // get by name
+ for (int i = 0; i < m_Nodes.GetSize(); i++) {
+ if ((m_Nodes[i]->m_Type == OBJECT_ENTITY && scumm_stricmp(m_Nodes[i]->m_Entity->m_Name, val->GetString()) == 0) ||
+ (m_Nodes[i]->m_Type == OBJECT_REGION && scumm_stricmp(m_Nodes[i]->m_Region->m_Name, val->GetString()) == 0)) {
+ node = i;
+ break;
+ }
+ }
+ }
+
+ if (node < 0 || node >= m_Nodes.GetSize()) Stack->PushNULL();
+ else {
+ switch (m_Nodes[node]->m_Type) {
+ case OBJECT_ENTITY:
+ Stack->PushNative(m_Nodes[node]->m_Entity, true);
+ break;
+ case OBJECT_REGION:
+ Stack->PushNative(m_Nodes[node]->m_Region, true);
+ break;
+ default:
+ Stack->PushNULL();
+ }
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddRegion / AddEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddRegion") == 0 || strcmp(Name, "AddEntity") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdSceneNode *Node = new CAdSceneNode(Game);
+ if (strcmp(Name, "AddRegion") == 0) {
+ CAdRegion *Region = new CAdRegion(Game);
+ if (!Val->IsNULL()) Region->SetName(Val->GetString());
+ Node->SetRegion(Region);
+ Stack->PushNative(Region, true);
+ } else {
+ CAdEntity *Entity = new CAdEntity(Game);
+ if (!Val->IsNULL()) Entity->SetName(Val->GetString());
+ Node->SetEntity(Entity);
+ Stack->PushNative(Entity, true);
+ }
+ m_Nodes.Add(Node);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InsertRegion / InsertEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InsertRegion") == 0 || strcmp(Name, "InsertEntity") == 0) {
+ Stack->CorrectParams(2);
+ int Index = Stack->Pop()->GetInt();
+ CScValue *Val = Stack->Pop();
+
+ CAdSceneNode *Node = new CAdSceneNode(Game);
+ if (strcmp(Name, "InsertRegion") == 0) {
+ CAdRegion *Region = new CAdRegion(Game);
+ if (!Val->IsNULL()) Region->SetName(Val->GetString());
+ Node->SetRegion(Region);
+ Stack->PushNative(Region, true);
+ } else {
+ CAdEntity *Entity = new CAdEntity(Game);
+ if (!Val->IsNULL()) Entity->SetName(Val->GetString());
+ Node->SetEntity(Entity);
+ Stack->PushNative(Entity, true);
+ }
+ if (Index < 0) Index = 0;
+ if (Index <= m_Nodes.GetSize() - 1) m_Nodes.InsertAt(Index, Node);
+ else m_Nodes.Add(Node);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteNode
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DeleteNode") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdSceneNode *ToDelete = NULL;
+ if (Val->IsNative()) {
+ CBScriptable *Temp = Val->GetNative();
+ for (int i = 0; i < m_Nodes.GetSize(); i++) {
+ if (m_Nodes[i]->m_Region == Temp || m_Nodes[i]->m_Entity == Temp) {
+ ToDelete = m_Nodes[i];
+ break;
+ }
+ }
+ } else {
+ int Index = Val->GetInt();
+ if (Index >= 0 && Index < m_Nodes.GetSize()) {
+ ToDelete = m_Nodes[Index];
+ }
+ }
+ if (ToDelete == NULL) {
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ for (int i = 0; i < m_Nodes.GetSize(); i++) {
+ if (m_Nodes[i] == ToDelete) {
+ delete m_Nodes[i];
+ m_Nodes[i] = NULL;
+ m_Nodes.RemoveAt(i);
+ break;
+ }
+ }
+ Stack->PushBool(true);
+ return S_OK;
+ }
+
+ else return CBObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdLayer::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("layer");
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumNodes (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumNodes") == 0) {
+ m_ScValue->SetInt(m_Nodes.GetSize());
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Width
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ m_ScValue->SetInt(m_Width);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Height
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ m_ScValue->SetInt(m_Height);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Main (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Main") == 0) {
+ m_ScValue->SetBool(m_Main);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CloseUp
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CloseUp") == 0) {
+ m_ScValue->SetBool(m_CloseUp);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ m_ScValue->SetBool(m_Active);
+ return m_ScValue;
+ }
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::ScSetProperty(char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CloseUp
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CloseUp") == 0) {
+ m_CloseUp = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Width
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ m_Width = Value->GetInt();
+ if (m_Width < 0) m_Width = 0;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Height
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ m_Height = Value->GetInt();
+ if (m_Height < 0) m_Height = 0;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ bool b = Value->GetBool();
+ if (b == false && m_Main) {
+ Game->LOG(0, "Warning: cannot deactivate scene's main layer");
+ } else m_Active = b;
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdLayer::ScToString() {
+ return "[layer]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "LAYER {\n");
+ Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", m_Name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+ Buffer->PutTextIndent(Indent + 2, "MAIN=%s\n", m_Main ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "WIDTH=%d\n", m_Width);
+ Buffer->PutTextIndent(Indent + 2, "HEIGHT=%d\n", m_Height);
+ Buffer->PutTextIndent(Indent + 2, "ACTIVE=%s\n", m_Active ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", m_EditorSelected ? "TRUE" : "FALSE");
+ if (m_CloseUp)
+ Buffer->PutTextIndent(Indent + 2, "CLOSE_UP=%s\n", m_CloseUp ? "TRUE" : "FALSE");
+
+ int i;
+
+ for (i = 0; i < m_Scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_Filename);
+ }
+
+ if (m_ScProp) m_ScProp->SaveAsText(Buffer, Indent + 2);
+
+ for (i = 0; i < m_Nodes.GetSize(); i++) {
+ switch (m_Nodes[i]->m_Type) {
+ case OBJECT_ENTITY:
+ m_Nodes[i]->m_Entity->SaveAsText(Buffer, Indent + 2);
+ break;
+ case OBJECT_REGION:
+ m_Nodes[i]->m_Region->SaveAsText(Buffer, Indent + 2);
+ break;
+ }
+ }
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Active));
+ PersistMgr->Transfer(TMEMBER(m_CloseUp));
+ PersistMgr->Transfer(TMEMBER(m_Height));
+ PersistMgr->Transfer(TMEMBER(m_Main));
+ m_Nodes.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_Width));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdLayer.h b/engines/wintermute/AdLayer.h
new file mode 100644
index 0000000000..eda3e6f272
--- /dev/null
+++ b/engines/wintermute/AdLayer.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdLayer_H__
+#define __WmeAdLayer_H__
+
+namespace WinterMute {
+class CAdSceneNode;
+class CAdLayer : public CBObject {
+public:
+ bool m_CloseUp;
+ DECLARE_PERSISTENT(CAdLayer, CBObject)
+ bool m_Active;
+ int m_Height;
+ int m_Width;
+ bool m_Main;
+ CAdLayer(CBGame *inGame);
+ virtual ~CAdLayer();
+ CBArray<CAdSceneNode *, CAdSceneNode *> m_Nodes;
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(char *Name);
+ virtual HRESULT ScSetProperty(char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name);
+ virtual char *ScToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdNodeState.cpp b/engines/wintermute/AdNodeState.cpp
new file mode 100644
index 0000000000..da2f4a39b9
--- /dev/null
+++ b/engines/wintermute/AdNodeState.cpp
@@ -0,0 +1,169 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "BGame.h"
+#include "AdNodeState.h"
+#include "AdEntity.h"
+#include "BStringTable.h"
+#include "BSprite.h"
+#include "utils.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdNodeState, false)
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdNodeState::CAdNodeState(CBGame *inGame): CBBase(inGame) {
+ m_Name = NULL;
+ m_Active = false;
+ for (int i = 0; i < 7; i++) m_Caption[i] = NULL;
+ m_AlphaColor = 0;
+ m_Filename = NULL;
+ m_Cursor = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdNodeState::~CAdNodeState() {
+ delete[] m_Name;
+ delete[] m_Filename;
+ delete[] m_Cursor;
+ m_Name = NULL;
+ m_Filename = NULL;
+ m_Cursor = NULL;
+ for (int i = 0; i < 7; i++) {
+ delete[] m_Caption[i];
+ m_Caption[i] = NULL;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetName(char *Name) {
+ delete[] m_Name;
+ m_Name = NULL;
+ CBUtils::SetString(&m_Name, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetFilename(char *Filename) {
+ delete[] m_Filename;
+ m_Filename = NULL;
+ CBUtils::SetString(&m_Filename, Filename);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetCursor(char *Filename) {
+ delete[] m_Cursor;
+ m_Cursor = NULL;
+ CBUtils::SetString(&m_Cursor, Filename);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdNodeState::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(Game));
+
+ PersistMgr->Transfer(TMEMBER(m_Active));
+ PersistMgr->Transfer(TMEMBER(m_Name));
+ PersistMgr->Transfer(TMEMBER(m_Filename));
+ PersistMgr->Transfer(TMEMBER(m_Cursor));
+ PersistMgr->Transfer(TMEMBER(m_AlphaColor));
+ for (int i = 0; i < 7; i++) PersistMgr->Transfer(TMEMBER(m_Caption[i]));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetCaption(char *Caption, int Case) {
+ if (Case == 0) Case = 1;
+ if (Case < 1 || Case > 7) return;
+
+ delete[] m_Caption[Case - 1];
+ m_Caption[Case - 1] = new char[strlen(Caption) + 1];
+ if (m_Caption[Case - 1]) {
+ strcpy(m_Caption[Case - 1], Caption);
+ Game->m_StringTable->Expand(&m_Caption[Case - 1]);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdNodeState::GetCaption(int Case) {
+ if (Case == 0) Case = 1;
+ if (Case < 1 || Case > 7 || m_Caption[Case - 1] == NULL) return "";
+ else return m_Caption[Case - 1];
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdNodeState::TransferEntity(CAdEntity *Entity, bool IncludingSprites, bool Saving) {
+ if (!Entity) return E_FAIL;
+
+ // hack!
+ if (this->Game != Entity->Game) this->Game = Entity->Game;
+
+ if (Saving) {
+ for (int i = 0; i < 7; i++) {
+ if (Entity->m_Caption[i]) SetCaption(Entity->m_Caption[i], i);
+ }
+ if (!Entity->m_Region && Entity->m_Sprite && Entity->m_Sprite->m_Filename) {
+ if (IncludingSprites) SetFilename(Entity->m_Sprite->m_Filename);
+ else SetFilename("");
+ }
+ if (Entity->m_Cursor && Entity->m_Cursor->m_Filename) SetCursor(Entity->m_Cursor->m_Filename);
+ m_AlphaColor = Entity->m_AlphaColor;
+ m_Active = Entity->m_Active;
+ } else {
+ for (int i = 0; i < 7; i++) {
+ if (m_Caption[i]) Entity->SetCaption(m_Caption[i], i);
+ }
+ if (m_Filename && !Entity->m_Region && IncludingSprites && strcmp(m_Filename, "") != 0) {
+ if (!Entity->m_Sprite || !Entity->m_Sprite->m_Filename || scumm_stricmp(Entity->m_Sprite->m_Filename, m_Filename) != 0)
+ Entity->SetSprite(m_Filename);
+ }
+ if (m_Cursor) {
+ if (!Entity->m_Cursor || !Entity->m_Cursor->m_Filename || scumm_stricmp(Entity->m_Cursor->m_Filename, m_Cursor) != 0)
+ Entity->SetCursor(m_Cursor);
+ }
+
+ Entity->m_Active = m_Active;
+ Entity->m_AlphaColor = m_AlphaColor;
+ }
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdNodeState.h b/engines/wintermute/AdNodeState.h
new file mode 100644
index 0000000000..722d880c33
--- /dev/null
+++ b/engines/wintermute/AdNodeState.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdNodeState_H__
+#define __WmeAdNodeState_H__
+
+namespace WinterMute {
+
+class CAdEntity;
+
+class CAdNodeState : public CBBase {
+public:
+ HRESULT TransferEntity(CAdEntity *Entity, bool IncludingSprites, bool Saving);
+ void SetName(char *Name);
+ void SetFilename(char *Filename);
+ void SetCursor(char *Filename);
+ DECLARE_PERSISTENT(CAdNodeState, CBBase)
+ CAdNodeState(CBGame *inGame);
+ virtual ~CAdNodeState();
+ char *m_Name;
+ bool m_Active;
+ char *m_Caption[7];
+ void SetCaption(char *Caption, int Case);
+ char *GetCaption(int Case);
+ uint32 m_AlphaColor;
+ char *m_Filename;
+ char *m_Cursor;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdObject.cpp b/engines/wintermute/AdObject.cpp
new file mode 100644
index 0000000000..4454d1d0f6
--- /dev/null
+++ b/engines/wintermute/AdObject.cpp
@@ -0,0 +1,1190 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdObject.h"
+#include "AdScene.h"
+#include "BGame.h"
+#include "BFrame.h"
+#include "BSound.h"
+#include "BSurfaceStorage.h"
+#include "ScValue.h"
+#include "AdGame.h"
+#include "AdLayer.h"
+#include "AdSceneNode.h"
+#include "AdInventory.h"
+#include "AdWaypointGroup.h"
+#include "AdItem.h"
+#include "BSubFrame.h"
+#include "BFont.h"
+#include "BFontStorage.h"
+#include "ScEngine.h"
+#include "BStringTable.h"
+#include "AdSentence.h"
+#include "ScScript.h"
+#include "BSprite.h"
+#include "ScStack.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdObject, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdObject::CAdObject(CBGame *inGame): CBObject(inGame) {
+ m_Type = OBJECT_NONE;
+ m_State = m_NextState = STATE_NONE;
+
+ m_Active = true;
+ m_Drawn = false;
+
+ m_CurrentSprite = NULL;
+ m_AnimSprite = NULL;
+ m_TempSprite2 = NULL;
+
+ m_Font = NULL;
+
+ m_Sentence = NULL;
+
+ m_ForcedTalkAnimName = NULL;
+ m_ForcedTalkAnimUsed = false;
+
+ m_BlockRegion = NULL;
+ m_WptGroup = NULL;
+
+ m_CurrentBlockRegion = NULL;
+ m_CurrentWptGroup = NULL;
+
+ m_IgnoreItems = false;
+ m_SceneIndependent = false;
+
+ m_StickRegion = NULL;
+
+ m_SubtitlesModRelative = true;
+ m_SubtitlesModX = 0;
+ m_SubtitlesModY = 0;
+ m_SubtitlesWidth = 0;
+ m_SubtitlesModXCenter = true;
+
+ m_Inventory = NULL;
+
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) m_CurrentRegions[i] = NULL;
+
+ m_PartEmitter = NULL;
+ m_PartFollowParent = false;
+ m_PartOffsetX = m_PartOffsetY = 0;
+
+ m_RegisterAlias = this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdObject::~CAdObject() {
+ m_CurrentSprite = NULL; // reference only, don't delete
+ SAFE_DELETE(m_AnimSprite);
+ SAFE_DELETE(m_Sentence);
+ SAFE_DELETE_ARRAY(m_ForcedTalkAnimName);
+
+ SAFE_DELETE(m_BlockRegion);
+ SAFE_DELETE(m_WptGroup);
+
+ SAFE_DELETE(m_CurrentBlockRegion);
+ SAFE_DELETE(m_CurrentWptGroup);
+
+
+ m_TempSprite2 = NULL; // reference only
+ m_StickRegion = NULL;
+
+ if (m_Font) Game->m_FontStorage->RemoveFont(m_Font);
+
+ if (m_Inventory) {
+ ((CAdGame *)Game)->UnregisterInventory(m_Inventory);
+ m_Inventory = NULL;
+ }
+
+ if (m_PartEmitter)
+ Game->UnregisterObject(m_PartEmitter);
+
+
+ for (int i = 0; i < m_AttachmentsPre.GetSize(); i++) {
+ Game->UnregisterObject(m_AttachmentsPre[i]);
+ }
+ m_AttachmentsPre.RemoveAll();
+
+ for (int i = 0; i < m_AttachmentsPost.GetSize(); i++) {
+ Game->UnregisterObject(m_AttachmentsPost[i]);
+ }
+ m_AttachmentsPost.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::PlayAnim(char *Filename) {
+ SAFE_DELETE(m_AnimSprite);
+ m_AnimSprite = new CBSprite(Game, this);
+ if (!m_AnimSprite) {
+ Game->LOG(0, "CAdObject::PlayAnim: error creating temp sprite (object:\"%s\" sprite:\"%s\")", m_Name, Filename);
+ return E_FAIL;
+ }
+ HRESULT res = m_AnimSprite->LoadFile(Filename);
+ if (FAILED(res)) {
+ Game->LOG(res, "CAdObject::PlayAnim: error loading temp sprite (object:\"%s\" sprite:\"%s\")", m_Name, Filename);
+ SAFE_DELETE(m_AnimSprite);
+ return res;
+ }
+ m_State = STATE_PLAYING_ANIM;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::Display() {
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::Update() {
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // PlayAnim / PlayAnimAsync
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "PlayAnim") == 0 || strcmp(Name, "PlayAnimAsync") == 0) {
+ Stack->CorrectParams(1);
+ if (FAILED(PlayAnim(Stack->Pop()->GetString()))) Stack->PushBool(false);
+ else {
+ if (strcmp(Name, "PlayAnimAsync") != 0) Script->WaitFor(this);
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Reset
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Reset") == 0) {
+ Stack->CorrectParams(0);
+ Reset();
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsTalking
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsTalking") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushBool(m_State == STATE_TALKING);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StopTalk / StopTalking
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StopTalk") == 0 || strcmp(Name, "StopTalking") == 0) {
+ Stack->CorrectParams(0);
+ if (m_Sentence) m_Sentence->Finish();
+ if (m_State == STATE_TALKING) {
+ m_State = m_NextState;
+ m_NextState = STATE_READY;
+ Stack->PushBool(true);
+ } else Stack->PushBool(false);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ForceTalkAnim
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ForceTalkAnim") == 0) {
+ Stack->CorrectParams(1);
+ char *AnimName = Stack->Pop()->GetString();
+ SAFE_DELETE_ARRAY(m_ForcedTalkAnimName);
+ m_ForcedTalkAnimName = new char[strlen(AnimName) + 1];
+ strcpy(m_ForcedTalkAnimName, AnimName);
+ m_ForcedTalkAnimUsed = false;
+ Stack->PushBool(true);
+ return S_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Talk / TalkAsync
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Talk") == 0 || strcmp(Name, "TalkAsync") == 0) {
+ Stack->CorrectParams(5);
+
+ char *Text = Stack->Pop()->GetString();
+ CScValue *SoundVal = Stack->Pop();
+ int Duration = Stack->Pop()->GetInt();
+ CScValue *ValStances = Stack->Pop();
+
+ char *Stances = ValStances->IsNULL() ? NULL : ValStances->GetString();
+
+ int Align;
+ CScValue *val = Stack->Pop();
+ if (val->IsNULL()) Align = TAL_CENTER;
+ else Align = val->GetInt();
+
+ Align = std::min(std::max(0, Align), NUM_TEXT_ALIGN - 1);
+
+ char *Sound = SoundVal->IsNULL() ? NULL : SoundVal->GetString();
+
+ Talk(Text, Sound, Duration, Stances, (TTextAlign)Align);
+ if (strcmp(Name, "TalkAsync") != 0) Script->WaitForExclusive(this);
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StickToRegion
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StickToRegion") == 0) {
+ Stack->CorrectParams(1);
+
+ CAdLayer *Main = ((CAdGame *)Game)->m_Scene->m_MainLayer;
+ bool RegFound = false;
+
+ int i;
+ CScValue *Val = Stack->Pop();
+ if (Val->IsNULL() || !Main) {
+ m_StickRegion = NULL;
+ RegFound = true;
+ } else if (Val->IsString()) {
+ char *RegionName = Val->GetString();
+ for (i = 0; i < Main->m_Nodes.GetSize(); i++) {
+ if (Main->m_Nodes[i]->m_Type == OBJECT_REGION && Main->m_Nodes[i]->m_Region->m_Name && scumm_stricmp(Main->m_Nodes[i]->m_Region->m_Name, RegionName) == 0) {
+ m_StickRegion = Main->m_Nodes[i]->m_Region;
+ RegFound = true;
+ break;
+ }
+ }
+ } else if (Val->IsNative()) {
+ CBScriptable *Obj = Val->GetNative();
+
+ for (i = 0; i < Main->m_Nodes.GetSize(); i++) {
+ if (Main->m_Nodes[i]->m_Type == OBJECT_REGION && Main->m_Nodes[i]->m_Region == Obj) {
+ m_StickRegion = Main->m_Nodes[i]->m_Region;
+ RegFound = true;
+ break;
+ }
+ }
+
+ }
+
+ if (!RegFound) m_StickRegion = NULL;
+ Stack->PushBool(RegFound);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetFont
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SetFont") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ if (Val->IsNULL()) SetFont(NULL);
+ else SetFont(Val->GetString());
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetFont
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetFont") == 0) {
+ Stack->CorrectParams(0);
+ if (m_Font && m_Font->m_Filename) Stack->PushString(m_Font->m_Filename);
+ else Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TakeItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TakeItem") == 0) {
+ Stack->CorrectParams(2);
+
+ if (!m_Inventory) {
+ m_Inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(m_Inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (!val->IsNULL()) {
+ char *ItemName = val->GetString();
+ val = Stack->Pop();
+ char *InsertAfter = val->IsNULL() ? NULL : val->GetString();
+ if (FAILED(m_Inventory->InsertItem(ItemName, InsertAfter))) Script->RuntimeError("Cannot add item '%s' to inventory", ItemName);
+ else {
+ // hide associated entities
+ ((CAdGame *)Game)->m_Scene->HandleItemAssociations(ItemName, false);
+ }
+
+ } else Script->RuntimeError("TakeItem: item name expected");
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DropItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DropItem") == 0) {
+ Stack->CorrectParams(1);
+
+ if (!m_Inventory) {
+ m_Inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(m_Inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (!val->IsNULL()) {
+ if (FAILED(m_Inventory->RemoveItem(val->GetString()))) Script->RuntimeError("Cannot remove item '%s' from inventory", val->GetString());
+ else {
+ // show associated entities
+ ((CAdGame *)Game)->m_Scene->HandleItemAssociations(val->GetString(), true);
+ }
+ } else Script->RuntimeError("DropItem: item name expected");
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetItem") == 0) {
+ Stack->CorrectParams(1);
+
+ if (!m_Inventory) {
+ m_Inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(m_Inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (val->m_Type == VAL_STRING) {
+ CAdItem *item = ((CAdGame *)Game)->GetItemByName(val->GetString());
+ if (item) Stack->PushNative(item, true);
+ else Stack->PushNULL();
+ } else if (val->IsNULL() || val->GetInt() < 0 || val->GetInt() >= m_Inventory->m_TakenItems.GetSize())
+ Stack->PushNULL();
+ else
+ Stack->PushNative(m_Inventory->m_TakenItems[val->GetInt()], true);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HasItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "HasItem") == 0) {
+ Stack->CorrectParams(1);
+
+ if (!m_Inventory) {
+ m_Inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(m_Inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (!val->IsNULL()) {
+ for (int i = 0; i < m_Inventory->m_TakenItems.GetSize(); i++) {
+ if (val->GetNative() == m_Inventory->m_TakenItems[i]) {
+ Stack->PushBool(true);
+ return S_OK;
+ } else if (scumm_stricmp(val->GetString(), m_Inventory->m_TakenItems[i]->m_Name) == 0) {
+ Stack->PushBool(true);
+ return S_OK;
+ }
+ }
+ } else Script->RuntimeError("HasItem: item name expected");
+
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateParticleEmitter
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CreateParticleEmitter") == 0) {
+ Stack->CorrectParams(3);
+ bool FollowParent = Stack->Pop()->GetBool();
+ int OffsetX = Stack->Pop()->GetInt();
+ int OffsetY = Stack->Pop()->GetInt();
+
+ CPartEmitter *Emitter = CreateParticleEmitter(FollowParent, OffsetX, OffsetY);
+ if (Emitter) Stack->PushNative(m_PartEmitter, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteParticleEmitter
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DeleteParticleEmitter") == 0) {
+ Stack->CorrectParams(0);
+ if (m_PartEmitter) {
+ Game->UnregisterObject(m_PartEmitter);
+ m_PartEmitter = NULL;
+ }
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddAttachment
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddAttachment") == 0) {
+ Stack->CorrectParams(4);
+ char *Filename = Stack->Pop()->GetString();
+ bool PreDisplay = Stack->Pop()->GetBool(true);
+ int OffsetX = Stack->Pop()->GetInt();
+ int OffsetY = Stack->Pop()->GetInt();
+
+ HRESULT res;
+ CAdEntity *Ent = new CAdEntity(Game);
+ if (FAILED(res = Ent->LoadFile(Filename))) {
+ SAFE_DELETE(Ent);
+ Script->RuntimeError("AddAttachment() failed loading entity '%s'", Filename);
+ Stack->PushBool(false);
+ } else {
+ Game->RegisterObject(Ent);
+
+ Ent->m_PosX = OffsetX;
+ Ent->m_PosY = OffsetY;
+ Ent->m_Active = true;
+
+ if (PreDisplay) m_AttachmentsPre.Add(Ent);
+ else m_AttachmentsPost.Add(Ent);
+
+ Stack->PushBool(true);
+ }
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // RemoveAttachment
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "RemoveAttachment") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+ bool Found = false;
+ if (Val->IsNative()) {
+ CBScriptable *Obj = Val->GetNative();
+ for (int i = 0; i < m_AttachmentsPre.GetSize(); i++) {
+ if (m_AttachmentsPre[i] == Obj) {
+ Found = true;
+ Game->UnregisterObject(m_AttachmentsPre[i]);
+ m_AttachmentsPre.RemoveAt(i);
+ i--;
+ }
+ }
+ for (int i = 0; i < m_AttachmentsPost.GetSize(); i++) {
+ if (m_AttachmentsPost[i] == Obj) {
+ Found = true;
+ Game->UnregisterObject(m_AttachmentsPost[i]);
+ m_AttachmentsPost.RemoveAt(i);
+ i--;
+ }
+ }
+ } else {
+ char *Name = Val->GetString();
+ for (int i = 0; i < m_AttachmentsPre.GetSize(); i++) {
+ if (m_AttachmentsPre[i]->m_Name && scumm_stricmp(m_AttachmentsPre[i]->m_Name, Name) == 0) {
+ Found = true;
+ Game->UnregisterObject(m_AttachmentsPre[i]);
+ m_AttachmentsPre.RemoveAt(i);
+ i--;
+ }
+ }
+ for (int i = 0; i < m_AttachmentsPost.GetSize(); i++) {
+ if (m_AttachmentsPost[i]->m_Name && scumm_stricmp(m_AttachmentsPost[i]->m_Name, Name) == 0) {
+ Found = true;
+ Game->UnregisterObject(m_AttachmentsPost[i]);
+ m_AttachmentsPost.RemoveAt(i);
+ i--;
+ }
+ }
+ }
+ Stack->PushBool(Found);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetAttachment
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetAttachment") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdObject *Ret = NULL;
+ if (Val->IsInt()) {
+ int Index = Val->GetInt();
+ int CurrIndex = 0;
+ for (int i = 0; i < m_AttachmentsPre.GetSize(); i++) {
+ if (CurrIndex == Index) Ret = m_AttachmentsPre[i];
+ CurrIndex++;
+ }
+ for (int i = 0; i < m_AttachmentsPost.GetSize(); i++) {
+ if (CurrIndex == Index) Ret = m_AttachmentsPost[i];
+ CurrIndex++;
+ }
+ } else {
+ char *Name = Val->GetString();
+ for (int i = 0; i < m_AttachmentsPre.GetSize(); i++) {
+ if (m_AttachmentsPre[i]->m_Name && scumm_stricmp(m_AttachmentsPre[i]->m_Name, Name) == 0) {
+ Ret = m_AttachmentsPre[i];
+ break;
+ }
+ }
+ if (!Ret) {
+ for (int i = 0; i < m_AttachmentsPost.GetSize(); i++) {
+ if (m_AttachmentsPost[i]->m_Name && scumm_stricmp(m_AttachmentsPost[i]->m_Name, Name) == 0) {
+ Ret = m_AttachmentsPre[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if (Ret != NULL) Stack->PushNative(Ret, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ else return CBObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdObject::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("object");
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ m_ScValue->SetBool(m_Active);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IgnoreItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IgnoreItems") == 0) {
+ m_ScValue->SetBool(m_IgnoreItems);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SceneIndependent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SceneIndependent") == 0) {
+ m_ScValue->SetBool(m_SceneIndependent);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesWidth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesWidth") == 0) {
+ m_ScValue->SetInt(m_SubtitlesWidth);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosRelative
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosRelative") == 0) {
+ m_ScValue->SetBool(m_SubtitlesModRelative);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosX") == 0) {
+ m_ScValue->SetInt(m_SubtitlesModX);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosY") == 0) {
+ m_ScValue->SetInt(m_SubtitlesModY);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosXCenter
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosXCenter") == 0) {
+ m_ScValue->SetBool(m_SubtitlesModXCenter);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumItems (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumItems") == 0) {
+ m_ScValue->SetInt(GetInventory()->m_TakenItems.GetSize());
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ParticleEmitter (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ParticleEmitter") == 0) {
+ if (m_PartEmitter) m_ScValue->SetNative(m_PartEmitter, true);
+ else m_ScValue->SetNULL();
+
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumAttachments (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumAttachments") == 0) {
+ m_ScValue->SetInt(m_AttachmentsPre.GetSize() + m_AttachmentsPost.GetSize());
+ return m_ScValue;
+ }
+
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::ScSetProperty(char *Name, CScValue *Value) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Active") == 0) {
+ m_Active = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IgnoreItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IgnoreItems") == 0) {
+ m_IgnoreItems = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SceneIndependent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SceneIndependent") == 0) {
+ m_SceneIndependent = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesWidth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesWidth") == 0) {
+ m_SubtitlesWidth = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosRelative
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosRelative") == 0) {
+ m_SubtitlesModRelative = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosX") == 0) {
+ m_SubtitlesModX = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosY") == 0) {
+ m_SubtitlesModY = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosXCenter
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosXCenter") == 0) {
+ m_SubtitlesModXCenter = Value->GetBool();
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdObject::ScToString() {
+ return "[ad object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::SetFont(char *Filename) {
+ if (m_Font) Game->m_FontStorage->RemoveFont(m_Font);
+ if (Filename) {
+ m_Font = Game->m_FontStorage->AddFont(Filename);
+ return m_Font == NULL ? E_FAIL : S_OK;
+ } else {
+ m_Font = NULL;
+ return S_OK;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdObject::GetHeight() {
+ if (!m_CurrentSprite) return 0;
+ else {
+ CBFrame *frame = m_CurrentSprite->m_Frames[m_CurrentSprite->m_CurrentFrame];
+ int ret = 0;
+ for (int i = 0; i < frame->m_Subframes.GetSize(); i++) {
+ ret = std::max(ret, frame->m_Subframes[i]->m_HotspotY);
+ }
+
+ if (m_Zoomable) {
+ float zoom = ((CAdGame *)Game)->m_Scene->GetZoomAt(m_PosX, m_PosY);
+ ret = ret * zoom / 100;
+ }
+ return ret;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdObject::Talk(char *Text, char *Sound, uint32 Duration, char *Stances, TTextAlign Align) {
+ if (!m_Sentence) m_Sentence = new CAdSentence(Game);
+ if (!m_Sentence) return;
+
+ if (m_ForcedTalkAnimName && m_ForcedTalkAnimUsed) {
+ SAFE_DELETE_ARRAY(m_ForcedTalkAnimName);
+ m_ForcedTalkAnimUsed = false;
+ }
+
+ SAFE_DELETE(m_Sentence->m_Sound);
+
+ m_Sentence->SetText(Text);
+ Game->m_StringTable->Expand(&m_Sentence->m_Text);
+ m_Sentence->SetStances(Stances);
+ m_Sentence->m_Duration = Duration;
+ m_Sentence->m_Align = Align;
+ m_Sentence->m_StartTime = Game->m_Timer;
+ m_Sentence->m_CurrentStance = -1;
+ m_Sentence->m_Font = m_Font == NULL ? Game->m_SystemFont : m_Font;
+ m_Sentence->m_Freezable = m_Freezable;
+
+ // try to locate speech file automatically
+ bool DeleteSound = false;
+ if (!Sound) {
+ char *Key = Game->m_StringTable->GetKey(Text);
+ if (Key) {
+ Sound = ((CAdGame *)Game)->FindSpeechFile(Key);
+ delete [] Key;
+
+ if (Sound) DeleteSound = true;
+ }
+ }
+
+ // load sound and set duration appropriately
+ if (Sound) {
+ CBSound *snd = new CBSound(Game);
+ if (snd && SUCCEEDED(snd->SetSound(Sound, SOUND_SPEECH, true))) {
+ m_Sentence->SetSound(snd);
+ if (m_Sentence->m_Duration <= 0) {
+ uint32 Length = snd->GetLength();
+ if (Length != 0) m_Sentence->m_Duration = Length;
+ }
+ } else delete snd;
+ }
+
+ // set duration by text length
+ if (m_Sentence->m_Duration <= 0) {
+ m_Sentence->m_Duration = MAX(1000, Game->m_SubtitlesSpeed * strlen(m_Sentence->m_Text));
+ }
+
+
+ int x, y, width, height;
+
+ x = m_PosX;
+ y = m_PosY;
+
+ if (!m_SceneIndependent && m_SubtitlesModRelative) {
+ x -= ((CAdGame *)Game)->m_Scene->GetOffsetLeft();
+ y -= ((CAdGame *)Game)->m_Scene->GetOffsetTop();
+ }
+
+
+ if (m_SubtitlesWidth > 0) width = m_SubtitlesWidth;
+ else {
+ if ((x < Game->m_Renderer->m_Width / 4 || x > Game->m_Renderer->m_Width * 0.75) && !Game->m_TouchInterface) {
+ width = std::max(Game->m_Renderer->m_Width / 4, std::min(x * 2, (Game->m_Renderer->m_Width - x) * 2));
+ } else width = Game->m_Renderer->m_Width / 2;
+ }
+
+ height = m_Sentence->m_Font->GetTextHeight((byte *)m_Sentence->m_Text, width);
+
+ y = y - height - GetHeight() - 5;
+ if (m_SubtitlesModRelative) {
+ x += m_SubtitlesModX;
+ y += m_SubtitlesModY;
+ } else {
+ x = m_SubtitlesModX;
+ y = m_SubtitlesModY;
+ }
+ if (m_SubtitlesModXCenter)
+ x = x - width / 2;
+
+
+ x = std::min(std::max(0, x), Game->m_Renderer->m_Width - width);
+ y = std::min(std::max(0, y), Game->m_Renderer->m_Height - height);
+
+ m_Sentence->m_Width = width;
+
+
+ m_Sentence->m_Pos.x = x;
+ m_Sentence->m_Pos.y = y;
+
+
+ if (m_SubtitlesModRelative) {
+ m_Sentence->m_Pos.x += ((CAdGame *)Game)->m_Scene->GetOffsetLeft();
+ m_Sentence->m_Pos.y += ((CAdGame *)Game)->m_Scene->GetOffsetTop();
+ }
+
+ m_Sentence->m_FixedPos = !m_SubtitlesModRelative;
+
+
+ m_Sentence->SetupTalkFile(Sound);
+
+ m_State = STATE_TALKING;
+
+ if (DeleteSound) delete [] Sound;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::Reset() {
+ if (m_State == STATE_PLAYING_ANIM && m_AnimSprite != NULL) {
+ SAFE_DELETE(m_AnimSprite);
+ } else if (m_State == STATE_TALKING && m_Sentence) {
+ m_Sentence->Finish();
+ }
+
+ m_State = m_NextState = STATE_READY;
+
+ Game->m_ScEngine->ResetObject(this);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Active));
+ PersistMgr->Transfer(TMEMBER(m_BlockRegion));
+ PersistMgr->Transfer(TMEMBER(m_CurrentBlockRegion));
+ PersistMgr->Transfer(TMEMBER(m_CurrentWptGroup));
+ PersistMgr->Transfer(TMEMBER(m_CurrentSprite));
+ PersistMgr->Transfer(TMEMBER(m_Drawn));
+ PersistMgr->Transfer(TMEMBER(m_Font));
+ PersistMgr->Transfer(TMEMBER(m_IgnoreItems));
+ PersistMgr->Transfer(TMEMBER_INT(m_NextState));
+ PersistMgr->Transfer(TMEMBER(m_Sentence));
+ PersistMgr->Transfer(TMEMBER_INT(m_State));
+ PersistMgr->Transfer(TMEMBER(m_AnimSprite));
+ PersistMgr->Transfer(TMEMBER(m_SceneIndependent));
+ PersistMgr->Transfer(TMEMBER(m_ForcedTalkAnimName));
+ PersistMgr->Transfer(TMEMBER(m_ForcedTalkAnimUsed));
+ PersistMgr->Transfer(TMEMBER(m_TempSprite2));
+ PersistMgr->Transfer(TMEMBER_INT(m_Type));
+ PersistMgr->Transfer(TMEMBER(m_WptGroup));
+ PersistMgr->Transfer(TMEMBER(m_StickRegion));
+ PersistMgr->Transfer(TMEMBER(m_SubtitlesModRelative));
+ PersistMgr->Transfer(TMEMBER(m_SubtitlesModX));
+ PersistMgr->Transfer(TMEMBER(m_SubtitlesModY));
+ PersistMgr->Transfer(TMEMBER(m_SubtitlesModXCenter));
+ PersistMgr->Transfer(TMEMBER(m_SubtitlesWidth));
+ PersistMgr->Transfer(TMEMBER(m_Inventory));
+ PersistMgr->Transfer(TMEMBER(m_PartEmitter));
+
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) PersistMgr->Transfer(TMEMBER(m_CurrentRegions[i]));
+
+ m_AttachmentsPre.Persist(PersistMgr);
+ m_AttachmentsPost.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_RegisterAlias));
+
+ PersistMgr->Transfer(TMEMBER(m_PartFollowParent));
+ PersistMgr->Transfer(TMEMBER(m_PartOffsetX));
+ PersistMgr->Transfer(TMEMBER(m_PartOffsetY));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdateSounds() {
+ if (m_Sentence && m_Sentence->m_Sound)
+ UpdateOneSound(m_Sentence->m_Sound);
+
+ return CBObject::UpdateSounds();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::ResetSoundPan() {
+ if (m_Sentence && m_Sentence->m_Sound) {
+ m_Sentence->m_Sound->SetPan(0.0f);
+ }
+ return CBObject::ResetSoundPan();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdObject::GetExtendedFlag(char *FlagName) {
+ if (!FlagName) return false;
+ else if (strcmp(FlagName, "usable") == 0) return true;
+
+ else return CBObject::GetExtendedFlag(FlagName);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ if (m_BlockRegion) m_BlockRegion->SaveAsText(Buffer, Indent + 2, "BLOCKED_REGION");
+ if (m_WptGroup) m_WptGroup->SaveAsText(Buffer, Indent + 2);
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdateBlockRegion() {
+ CAdGame *AdGame = (CAdGame *)Game;
+ if (AdGame->m_Scene) {
+ if (m_BlockRegion && m_CurrentBlockRegion)
+ m_CurrentBlockRegion->Mimic(m_BlockRegion, m_Zoomable ? AdGame->m_Scene->GetScaleAt(m_PosY) : 100.0f, m_PosX, m_PosY);
+
+ if (m_WptGroup && m_CurrentWptGroup)
+ m_CurrentWptGroup->Mimic(m_WptGroup, m_Zoomable ? AdGame->m_Scene->GetScaleAt(m_PosY) : 100.0f, m_PosX, m_PosY);
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventory *CAdObject::GetInventory() {
+ if (!m_Inventory) {
+ m_Inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(m_Inventory);
+ }
+ return m_Inventory;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::AfterMove() {
+ CAdRegion *NewRegions[MAX_NUM_REGIONS];
+
+ ((CAdGame *)Game)->m_Scene->GetRegionsAt(m_PosX, m_PosY, NewRegions, MAX_NUM_REGIONS);
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) {
+ if (!NewRegions[i]) break;
+ bool RegFound = false;
+ for (int j = 0; j < MAX_NUM_REGIONS; j++) {
+ if (m_CurrentRegions[j] == NewRegions[i]) {
+ m_CurrentRegions[j] = NULL;
+ RegFound = true;
+ break;
+ }
+ }
+ if (!RegFound) NewRegions[i]->ApplyEvent("ActorEntry");
+ }
+
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) {
+ if (m_CurrentRegions[i] && Game->ValidObject(m_CurrentRegions[i])) {
+ m_CurrentRegions[i]->ApplyEvent("ActorLeave");
+ }
+ m_CurrentRegions[i] = NewRegions[i];
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::InvalidateCurrRegions() {
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) m_CurrentRegions[i] = NULL;
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::GetScale(float *ScaleX, float *ScaleY) {
+ if (m_Zoomable) {
+ if (m_ScaleX >= 0 || m_ScaleY >= 0) {
+ *ScaleX = m_ScaleX < 0 ? 100 : m_ScaleX;
+ *ScaleY = m_ScaleY < 0 ? 100 : m_ScaleY;
+ } else if (m_Scale >= 0) *ScaleX = *ScaleY = m_Scale;
+ else *ScaleX = *ScaleY = ((CAdGame *)Game)->m_Scene->GetZoomAt(m_PosX, m_PosY) + m_RelativeScale;
+ } else {
+ *ScaleX = *ScaleY = 100;
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdateSpriteAttachments() {
+ for (int i = 0; i < m_AttachmentsPre.GetSize(); i++) {
+ m_AttachmentsPre[i]->Update();
+ }
+ for (int i = 0; i < m_AttachmentsPost.GetSize(); i++) {
+ m_AttachmentsPost[i]->Update();
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::DisplaySpriteAttachments(bool PreDisplay) {
+ if (PreDisplay) {
+ for (int i = 0; i < m_AttachmentsPre.GetSize(); i++) {
+ DisplaySpriteAttachment(m_AttachmentsPre[i]);
+ }
+ } else {
+ for (int i = 0; i < m_AttachmentsPost.GetSize(); i++) {
+ DisplaySpriteAttachment(m_AttachmentsPost[i]);
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::DisplaySpriteAttachment(CAdObject *Attachment) {
+ if (!Attachment->m_Active) return S_OK;
+
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+ int OrigX = Attachment->m_PosX;
+ int OrigY = Attachment->m_PosY;
+
+ // inherit position from owner
+ Attachment->m_PosX = this->m_PosX + Attachment->m_PosX * ScaleX / 100.0f;
+ Attachment->m_PosY = this->m_PosY + Attachment->m_PosY * ScaleY / 100.0f;
+
+ // inherit other props
+ Attachment->m_AlphaColor = this->m_AlphaColor;
+ Attachment->m_BlendMode = this->m_BlendMode;
+
+ Attachment->m_Scale = this->m_Scale;
+ Attachment->m_RelativeScale = this->m_RelativeScale;
+ Attachment->m_ScaleX = this->m_ScaleX;
+ Attachment->m_ScaleY = this->m_ScaleY;
+
+ Attachment->m_Rotate = this->m_Rotate;
+ Attachment->m_RelativeRotate = this->m_RelativeRotate;
+ Attachment->m_RotateValid = this->m_RotateValid;
+
+ Attachment->m_RegisterAlias = this;
+ Attachment->m_Registrable = this->m_Registrable;
+
+ HRESULT ret = Attachment->Display();
+
+ Attachment->m_PosX = OrigX;
+ Attachment->m_PosY = OrigY;
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CPartEmitter *CAdObject::CreateParticleEmitter(bool FollowParent, int OffsetX, int OffsetY) {
+ m_PartFollowParent = FollowParent;
+ m_PartOffsetX = OffsetX;
+ m_PartOffsetY = OffsetY;
+
+ if (!m_PartEmitter) {
+ m_PartEmitter = new CPartEmitter(Game, this);
+ if (m_PartEmitter) {
+ Game->RegisterObject(m_PartEmitter);
+ }
+ }
+ UpdatePartEmitter();
+ return m_PartEmitter;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdatePartEmitter() {
+ if (!m_PartEmitter) return E_FAIL;
+
+ if (m_PartFollowParent) {
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+ m_PartEmitter->m_PosX = m_PosX + (ScaleX / 100.0f) * m_PartOffsetX;
+ m_PartEmitter->m_PosY = m_PosY + (ScaleY / 100.0f) * m_PartOffsetY;
+ }
+ return m_PartEmitter->Update();
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdPath.cpp b/engines/wintermute/AdPath.cpp
new file mode 100644
index 0000000000..fb95f28450
--- /dev/null
+++ b/engines/wintermute/AdPath.cpp
@@ -0,0 +1,112 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdPath.h"
+#include "BPoint.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdPath, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdPath::CAdPath(CBGame *inGame): CBBase(inGame) {
+ m_CurrIndex = -1;
+ m_Ready = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdPath::~CAdPath() {
+ Reset();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdPath::Reset() {
+ for (int i = 0; i < m_Points.GetSize(); i++)
+ delete m_Points[i];
+
+ m_Points.RemoveAll();
+ m_CurrIndex = -1;
+ m_Ready = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBPoint *CAdPath::GetFirst() {
+ if (m_Points.GetSize() > 0) {
+ m_CurrIndex = 0;
+ return m_Points[m_CurrIndex];
+ } else return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBPoint *CAdPath::GetNext() {
+ m_CurrIndex++;
+ if (m_CurrIndex < m_Points.GetSize()) return m_Points[m_CurrIndex];
+ else return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBPoint *CAdPath::GetCurrent() {
+ if (m_CurrIndex >= 0 && m_CurrIndex < m_Points.GetSize()) return m_Points[m_CurrIndex];
+ else return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdPath::AddPoint(CBPoint *point) {
+ m_Points.Add(point);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdPath::SetReady(bool ready) {
+ bool orig = m_Ready;
+ m_Ready = ready;
+
+ return orig;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdPath::Persist(CBPersistMgr *PersistMgr) {
+
+ PersistMgr->Transfer(TMEMBER(Game));
+
+ PersistMgr->Transfer(TMEMBER(m_CurrIndex));
+ m_Points.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_Ready));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdPath.h b/engines/wintermute/AdPath.h
new file mode 100644
index 0000000000..a5424fcd70
--- /dev/null
+++ b/engines/wintermute/AdPath.h
@@ -0,0 +1,56 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdPath_H__
+#define __WmeAdPath_H__
+
+#include "persistent.h"
+#include "coll_templ.h"
+#include "BBase.h"
+
+namespace WinterMute {
+class CBPoint;
+class CAdPath : public CBBase {
+public:
+ DECLARE_PERSISTENT(CAdPath, CBBase)
+ CBPoint *GetCurrent();
+ bool SetReady(bool ready = true);
+ void AddPoint(CBPoint *point);
+ CBPoint *GetNext();
+ CBPoint *GetFirst();
+ void Reset();
+ CAdPath(CBGame *inGame);
+ virtual ~CAdPath();
+ CBArray <CBPoint *, CBPoint *> m_Points;
+ int m_CurrIndex;
+ bool m_Ready;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdPathPoint.cpp b/engines/wintermute/AdPathPoint.cpp
new file mode 100644
index 0000000000..3bffcd4c73
--- /dev/null
+++ b/engines/wintermute/AdPathPoint.cpp
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "AdPathPoint.h"
+#include "BPersistMgr.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdPathPoint, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdPathPoint::CAdPathPoint() {
+ x = y = 0;
+ m_Distance = 0;
+
+ m_Marked = false;
+ m_Origin = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdPathPoint::CAdPathPoint(int initX, int initY, int initDistance) {
+ x = initX;
+ y = initY;
+ m_Distance = initDistance;
+
+ m_Marked = false;
+ m_Origin = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdPathPoint::~CAdPathPoint() {
+ m_Origin = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdPathPoint::Persist(CBPersistMgr *PersistMgr) {
+
+ CBPoint::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Distance));
+ PersistMgr->Transfer(TMEMBER(m_Marked));
+ PersistMgr->Transfer(TMEMBER(m_Origin));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdPathPoint.h b/engines/wintermute/AdPathPoint.h
new file mode 100644
index 0000000000..0196f42701
--- /dev/null
+++ b/engines/wintermute/AdPathPoint.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdPathPoint_H__
+#define __WmeAdPathPoint_H__
+
+#include "persistent.h"
+#include "BPoint.h"
+
+namespace WinterMute {
+
+class CAdPathPoint : public CBPoint {
+public:
+ DECLARE_PERSISTENT(CAdPathPoint, CBPoint)
+ CAdPathPoint(int initX, int initY, int initDistance);
+ CAdPathPoint();
+ virtual ~CAdPathPoint();
+ CAdPathPoint *m_Origin;
+ bool m_Marked;
+ int m_Distance;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdRegion.cpp b/engines/wintermute/AdRegion.cpp
new file mode 100644
index 0000000000..71a36cf636
--- /dev/null
+++ b/engines/wintermute/AdRegion.cpp
@@ -0,0 +1,394 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdRegion.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "ScValue.h"
+#include "ScScript.h"
+#include "BGame.h"
+#include "BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdRegion, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdRegion::CAdRegion(CBGame *inGame): CBRegion(inGame) {
+ m_Blocked = false;
+ m_Decoration = false;
+ m_Zoom = 0;
+ m_Alpha = 0xFFFFFFFF;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdRegion::~CAdRegion() {
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdRegion::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing REGION file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(REGION)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(NAME)
+TOKEN_DEF(ACTIVE)
+TOKEN_DEF(ZOOM)
+TOKEN_DEF(SCALE)
+TOKEN_DEF(BLOCKED)
+TOKEN_DEF(DECORATION)
+TOKEN_DEF(POINT)
+TOKEN_DEF(ALPHA_COLOR)
+TOKEN_DEF(ALPHA)
+TOKEN_DEF(EDITOR_SELECTED_POINT)
+TOKEN_DEF(EDITOR_SELECTED)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PROPERTY)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(REGION)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(ACTIVE)
+ TOKEN_TABLE(ZOOM)
+ TOKEN_TABLE(SCALE)
+ TOKEN_TABLE(BLOCKED)
+ TOKEN_TABLE(DECORATION)
+ TOKEN_TABLE(POINT)
+ TOKEN_TABLE(ALPHA_COLOR)
+ TOKEN_TABLE(ALPHA)
+ TOKEN_TABLE(EDITOR_SELECTED_POINT)
+ TOKEN_TABLE(EDITOR_SELECTED)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PROPERTY)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_REGION) {
+ Game->LOG(0, "'REGION' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ int i;
+
+ for (i = 0; i < m_Points.GetSize(); i++) delete m_Points[i];
+ m_Points.RemoveAll();
+
+ int ar = 255, ag = 255, ab = 255, alpha = 255;
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ SetCaption((char *)params);
+ break;
+
+ case TOKEN_ACTIVE:
+ parser.ScanStr((char *)params, "%b", &m_Active);
+ break;
+
+ case TOKEN_BLOCKED:
+ parser.ScanStr((char *)params, "%b", &m_Blocked);
+ break;
+
+ case TOKEN_DECORATION:
+ parser.ScanStr((char *)params, "%b", &m_Decoration);
+ break;
+
+ case TOKEN_ZOOM:
+ case TOKEN_SCALE: {
+ int i;
+ parser.ScanStr((char *)params, "%d", &i);
+ m_Zoom = (float)i;
+ }
+ break;
+
+ case TOKEN_POINT: {
+ int x, y;
+ parser.ScanStr((char *)params, "%d,%d", &x, &y);
+ m_Points.Add(new CBPoint(x, y));
+ }
+ break;
+
+ case TOKEN_ALPHA_COLOR:
+ parser.ScanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab);
+ break;
+
+ case TOKEN_ALPHA:
+ parser.ScanStr((char *)params, "%d", &alpha);
+ break;
+
+ case TOKEN_EDITOR_SELECTED:
+ parser.ScanStr((char *)params, "%b", &m_EditorSelected);
+ break;
+
+ case TOKEN_EDITOR_SELECTED_POINT:
+ parser.ScanStr((char *)params, "%d", &m_EditorSelectedPoint);
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in REGION definition");
+ return E_FAIL;
+ }
+
+ CreateRegion();
+
+ m_Alpha = DRGBA(ar, ag, ab, alpha);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ /*
+ //////////////////////////////////////////////////////////////////////////
+ // SkipTo
+ //////////////////////////////////////////////////////////////////////////
+ if(strcmp(Name, "SkipTo")==0){
+ Stack->CorrectParams(2);
+ m_PosX = Stack->Pop()->GetInt();
+ m_PosY = Stack->Pop()->GetInt();
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ else*/ return CBRegion::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdRegion::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("ad region");
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Name") == 0) {
+ m_ScValue->SetString(m_Name);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Blocked
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Blocked") == 0) {
+ m_ScValue->SetBool(m_Blocked);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Decoration
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Decoration") == 0) {
+ m_ScValue->SetBool(m_Decoration);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Scale
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale") == 0) {
+ m_ScValue->SetFloat(m_Zoom);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AlphaColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AlphaColor") == 0) {
+ m_ScValue->SetInt((int)m_Alpha);
+ return m_ScValue;
+ }
+
+ else return CBRegion::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::ScSetProperty(char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Blocked
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Blocked") == 0) {
+ m_Blocked = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Decoration
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Decoration") == 0) {
+ m_Decoration = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Scale
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale") == 0) {
+ m_Zoom = Value->GetFloat();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AlphaColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AlphaColor") == 0) {
+ m_Alpha = (uint32)Value->GetInt();
+ return S_OK;
+ }
+
+ else return CBRegion::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdRegion::ScToString() {
+ return "[ad region]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "REGION {\n");
+ Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", m_Name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+ Buffer->PutTextIndent(Indent + 2, "BLOCKED=%s\n", m_Blocked ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "DECORATION=%s\n", m_Decoration ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "ACTIVE=%s\n", m_Active ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "SCALE=%d\n", (int)m_Zoom);
+ Buffer->PutTextIndent(Indent + 2, "ALPHA_COLOR { %d,%d,%d }\n", D3DCOLGetR(m_Alpha), D3DCOLGetG(m_Alpha), D3DCOLGetB(m_Alpha));
+ Buffer->PutTextIndent(Indent + 2, "ALPHA = %d\n", D3DCOLGetA(m_Alpha));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", m_EditorSelected ? "TRUE" : "FALSE");
+
+ int i;
+ for (i = 0; i < m_Scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_Filename);
+ }
+
+ if (m_ScProp) m_ScProp->SaveAsText(Buffer, Indent + 2);
+
+ for (i = 0; i < m_Points.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "POINT {%d,%d}\n", m_Points[i]->x, m_Points[i]->y);
+ }
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::Persist(CBPersistMgr *PersistMgr) {
+ CBRegion::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Alpha));
+ PersistMgr->Transfer(TMEMBER(m_Blocked));
+ PersistMgr->Transfer(TMEMBER(m_Decoration));
+ PersistMgr->Transfer(TMEMBER(m_Zoom));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdRegion.h b/engines/wintermute/AdRegion.h
new file mode 100644
index 0000000000..61bb4d2a58
--- /dev/null
+++ b/engines/wintermute/AdRegion.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdRegion_H__
+#define __WmeAdRegion_H__
+
+#include "BRegion.h"
+
+namespace WinterMute {
+
+class CAdRegion : public CBRegion {
+public:
+ DECLARE_PERSISTENT(CAdRegion, CBRegion)
+ uint32 m_Alpha;
+ float m_Zoom;
+ bool m_Blocked;
+ bool m_Decoration;
+ CAdRegion(CBGame *inGame);
+ virtual ~CAdRegion();
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(char *Name);
+ virtual HRESULT ScSetProperty(char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name);
+ virtual char *ScToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdResponse.cpp b/engines/wintermute/AdResponse.cpp
new file mode 100644
index 0000000000..e9a84b4bd4
--- /dev/null
+++ b/engines/wintermute/AdResponse.cpp
@@ -0,0 +1,143 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdResponse.h"
+#include "BGame.h"
+#include "BFontStorage.h"
+#include "BSprite.h"
+#include "utils.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdResponse, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponse::CAdResponse(CBGame *inGame): CBObject(inGame) {
+ m_Text = NULL;
+ m_TextOrig = NULL;
+ m_Icon = m_IconHover = m_IconPressed = NULL;
+ m_Font = NULL;
+ m_ID = 0;
+ m_ResponseType = RESPONSE_ALWAYS;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponse::~CAdResponse() {
+ delete[] m_Text;
+ delete[] m_TextOrig;
+ delete m_Icon;
+ delete m_IconHover;
+ delete m_IconPressed;
+ m_Text = NULL;
+ m_TextOrig = NULL;
+ m_Icon = NULL;
+ m_IconHover = NULL;
+ m_IconPressed = NULL;
+ if (m_Font) Game->m_FontStorage->RemoveFont(m_Font);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponse::SetText(char *Text) {
+ CBUtils::SetString(&m_Text, Text);
+ CBUtils::SetString(&m_TextOrig, Text);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetIcon(char *Filename) {
+ delete m_Icon;
+ m_Icon = new CBSprite(Game);
+ if (!m_Icon || FAILED(m_Icon->LoadFile(Filename))) {
+ Game->LOG(0, "CAdResponse::SetIcon failed for file '%s'", Filename);
+ delete m_Icon;
+ m_Icon = NULL;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetFont(char *Filename) {
+ if (m_Font) Game->m_FontStorage->RemoveFont(m_Font);
+ m_Font = Game->m_FontStorage->AddFont(Filename);
+ if (!m_Font) {
+ Game->LOG(0, "CAdResponse::SetFont failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetIconHover(char *Filename) {
+ delete m_IconHover;
+ m_IconHover = new CBSprite(Game);
+ if (!m_IconHover || FAILED(m_IconHover->LoadFile(Filename))) {
+ Game->LOG(0, "CAdResponse::SetIconHover failed for file '%s'", Filename);
+ delete m_IconHover;
+ m_IconHover = NULL;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetIconPressed(char *Filename) {
+ delete m_IconPressed;
+ m_IconPressed = new CBSprite(Game);
+ if (!m_IconPressed || FAILED(m_IconPressed->LoadFile(Filename))) {
+ Game->LOG(0, "CAdResponse::SetIconPressed failed for file '%s'", Filename);
+ delete m_IconPressed;
+ m_IconPressed = NULL;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Icon));
+ PersistMgr->Transfer(TMEMBER(m_IconHover));
+ PersistMgr->Transfer(TMEMBER(m_IconPressed));
+ PersistMgr->Transfer(TMEMBER(m_ID));
+ PersistMgr->Transfer(TMEMBER(m_Text));
+ PersistMgr->Transfer(TMEMBER(m_TextOrig));
+ PersistMgr->Transfer(TMEMBER_INT(m_ResponseType));
+ PersistMgr->Transfer(TMEMBER(m_Font));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdResponse.h b/engines/wintermute/AdResponse.h
new file mode 100644
index 0000000000..5c529f4b81
--- /dev/null
+++ b/engines/wintermute/AdResponse.h
@@ -0,0 +1,61 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdResponse_H__
+#define __WmeAdResponse_H__
+
+
+#include "BObject.h"
+#include "AdTypes.h"
+
+namespace WinterMute {
+class CBFont;
+class CAdResponse : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdResponse, CBObject)
+ HRESULT SetIcon(char *Filename);
+ HRESULT SetFont(char *Filename);
+ HRESULT SetIconHover(char *Filename);
+ HRESULT SetIconPressed(char *Filename);
+ void SetText(char *Text);
+ int m_ID;
+ CBSprite *m_Icon;
+ CBSprite *m_IconHover;
+ CBSprite *m_IconPressed;
+ CBFont *m_Font;
+ char *m_Text;
+ char *m_TextOrig;
+ CAdResponse(CBGame *inGame);
+ virtual ~CAdResponse();
+ TResponseType m_ResponseType;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdResponseBox.cpp b/engines/wintermute/AdResponseBox.cpp
new file mode 100644
index 0000000000..ff4407fcfc
--- /dev/null
+++ b/engines/wintermute/AdResponseBox.cpp
@@ -0,0 +1,631 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdGame.h"
+#include "AdResponseBox.h"
+#include "BParser.h"
+#include "BSurfaceStorage.h"
+#include "UIButton.h"
+#include "UIWindow.h"
+#include "BDynBuffer.h"
+#include "BFontStorage.h"
+#include "BFont.h"
+#include "AdResponse.h"
+#include "ScScript.h"
+#include "ScStack.h"
+#include "BSprite.h"
+#include "BFileManager.h"
+#include "utils.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdResponseBox, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseBox::CAdResponseBox(CBGame *inGame): CBObject(inGame) {
+ m_Font = m_FontHover = NULL;
+
+ m_Window = NULL;
+ m_ShieldWindow = new CUIWindow(Game);
+
+ m_Horizontal = false;
+ CBPlatform::SetRectEmpty(&m_ResponseArea);
+ m_ScrollOffset = 0;
+ m_Spacing = 0;
+
+ m_WaitingScript = NULL;
+ m_LastResponseText = NULL;
+ m_LastResponseTextOrig = NULL;
+
+ m_VerticalAlign = VAL_BOTTOM;
+ m_Align = TAL_LEFT;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseBox::~CAdResponseBox() {
+
+ SAFE_DELETE(m_Window);
+ SAFE_DELETE(m_ShieldWindow);
+ SAFE_DELETE_ARRAY(m_LastResponseText);
+ SAFE_DELETE_ARRAY(m_LastResponseTextOrig);
+
+ if (m_Font) Game->m_FontStorage->RemoveFont(m_Font);
+ if (m_FontHover) Game->m_FontStorage->RemoveFont(m_FontHover);
+
+ ClearResponses();
+ ClearButtons();
+
+ m_WaitingScript = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseBox::ClearResponses() {
+ for (int i = 0; i < m_Responses.GetSize(); i++) {
+ delete m_Responses[i];
+ }
+ m_Responses.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseBox::ClearButtons() {
+ for (int i = 0; i < m_RespButtons.GetSize(); i++) {
+ delete m_RespButtons[i];
+ }
+ m_RespButtons.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::InvalidateButtons() {
+ for (int i = 0; i < m_RespButtons.GetSize(); i++) {
+ m_RespButtons[i]->m_Image = NULL;
+ m_RespButtons[i]->m_Cursor = NULL;
+ m_RespButtons[i]->m_Font = NULL;
+ m_RespButtons[i]->m_FontHover = NULL;
+ m_RespButtons[i]->m_FontPress = NULL;
+ m_RespButtons[i]->SetText("");
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::CreateButtons() {
+ ClearButtons();
+
+ m_ScrollOffset = 0;
+ for (int i = 0; i < m_Responses.GetSize(); i++) {
+ CUIButton *btn = new CUIButton(Game);
+ if (btn) {
+ btn->m_Parent = m_Window;
+ btn->m_SharedFonts = btn->m_SharedImages = true;
+ btn->m_SharedCursors = true;
+ // iconic
+ if (m_Responses[i]->m_Icon) {
+ btn->m_Image = m_Responses[i]->m_Icon;
+ if (m_Responses[i]->m_IconHover) btn->m_ImageHover = m_Responses[i]->m_IconHover;
+ if (m_Responses[i]->m_IconPressed) btn->m_ImagePress = m_Responses[i]->m_IconPressed;
+
+ btn->SetCaption(m_Responses[i]->m_Text);
+ if (m_Cursor) btn->m_Cursor = m_Cursor;
+ else if (Game->m_ActiveCursor) btn->m_Cursor = Game->m_ActiveCursor;
+ }
+ // textual
+ else {
+ btn->SetText(m_Responses[i]->m_Text);
+ btn->m_Font = (m_Font == NULL) ? Game->m_SystemFont : m_Font;
+ btn->m_FontHover = (m_FontHover == NULL) ? Game->m_SystemFont : m_FontHover;
+ btn->m_FontPress = btn->m_FontHover;
+ btn->m_Align = m_Align;
+
+ if (Game->m_TouchInterface)
+ btn->m_FontHover = btn->m_Font;
+
+
+ if (m_Responses[i]->m_Font) btn->m_Font = m_Responses[i]->m_Font;
+
+ btn->m_Width = m_ResponseArea.right - m_ResponseArea.left;
+ if (btn->m_Width <= 0) btn->m_Width = Game->m_Renderer->m_Width;
+ }
+ btn->SetName("response");
+ btn->CorrectSize();
+
+ // make the responses touchable
+ if (Game->m_TouchInterface)
+ btn->m_Height = std::max(btn->m_Height, 50);
+
+ //btn->SetListener(this, btn, m_Responses[i]->m_ID);
+ btn->SetListener(this, btn, i);
+ btn->m_Visible = false;
+ m_RespButtons.Add(btn);
+
+ if (m_ResponseArea.bottom - m_ResponseArea.top < btn->m_Height) {
+ Game->LOG(0, "Warning: Response '%s' is too high to be displayed within response box. Correcting.", m_Responses[i]->m_Text);
+ m_ResponseArea.bottom += (btn->m_Height - (m_ResponseArea.bottom - m_ResponseArea.top));
+ }
+ }
+ }
+ m_Ready = false;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdResponseBox::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing RESPONSE_BOX file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(RESPONSE_BOX)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(FONT_HOVER)
+TOKEN_DEF(FONT)
+TOKEN_DEF(AREA)
+TOKEN_DEF(HORIZONTAL)
+TOKEN_DEF(SPACING)
+TOKEN_DEF(WINDOW)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(TEXT_ALIGN)
+TOKEN_DEF(VERTICAL_ALIGN)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(RESPONSE_BOX)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(FONT_HOVER)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(AREA)
+ TOKEN_TABLE(HORIZONTAL)
+ TOKEN_TABLE(SPACING)
+ TOKEN_TABLE(WINDOW)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(TEXT_ALIGN)
+ TOKEN_TABLE(VERTICAL_ALIGN)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_RESPONSE_BOX) {
+ Game->LOG(0, "'RESPONSE_BOX' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_WINDOW:
+ SAFE_DELETE(m_Window);
+ m_Window = new CUIWindow(Game);
+ if (!m_Window || FAILED(m_Window->LoadBuffer(params, false))) {
+ SAFE_DELETE(m_Window);
+ cmd = PARSERR_GENERIC;
+ } else if (m_ShieldWindow) m_ShieldWindow->m_Parent = m_Window;
+ break;
+
+ case TOKEN_FONT:
+ if (m_Font) Game->m_FontStorage->RemoveFont(m_Font);
+ m_Font = Game->m_FontStorage->AddFont((char *)params);
+ if (!m_Font) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_HOVER:
+ if (m_FontHover) Game->m_FontStorage->RemoveFont(m_FontHover);
+ m_FontHover = Game->m_FontStorage->AddFont((char *)params);
+ if (!m_FontHover) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_AREA:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_ResponseArea.left, &m_ResponseArea.top, &m_ResponseArea.right, &m_ResponseArea.bottom);
+ break;
+
+ case TOKEN_HORIZONTAL:
+ parser.ScanStr((char *)params, "%b", &m_Horizontal);
+ break;
+
+ case TOKEN_TEXT_ALIGN:
+ if (scumm_stricmp((char *)params, "center") == 0) m_Align = TAL_CENTER;
+ else if (scumm_stricmp((char *)params, "right") == 0) m_Align = TAL_RIGHT;
+ else m_Align = TAL_LEFT;
+ break;
+
+ case TOKEN_VERTICAL_ALIGN:
+ if (scumm_stricmp((char *)params, "top") == 0) m_VerticalAlign = VAL_TOP;
+ else if (scumm_stricmp((char *)params, "center") == 0) m_VerticalAlign = VAL_CENTER;
+ else m_VerticalAlign = VAL_BOTTOM;
+ break;
+
+ case TOKEN_SPACING:
+ parser.ScanStr((char *)params, "%d", &m_Spacing);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+
+ case TOKEN_CURSOR:
+ SAFE_DELETE(m_Cursor);
+ m_Cursor = new CBSprite(Game);
+ if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) {
+ SAFE_DELETE(m_Cursor);
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in RESPONSE_BOX definition");
+ return E_FAIL;
+ }
+
+ if (m_Window) {
+ for (int i = 0; i < m_Window->m_Widgets.GetSize(); i++) {
+ if (!m_Window->m_Widgets[i]->m_ListenerObject)
+ m_Window->m_Widgets[i]->SetListener(this, m_Window->m_Widgets[i], 0);
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "RESPONSE_BOX\n");
+ Buffer->PutTextIndent(Indent, "{\n");
+
+ Buffer->PutTextIndent(Indent + 2, "AREA { %d, %d, %d, %d }\n", m_ResponseArea.left, m_ResponseArea.top, m_ResponseArea.right, m_ResponseArea.bottom);
+
+ if (m_Font && m_Font->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", m_Font->m_Filename);
+ if (m_FontHover && m_FontHover->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "FONT_HOVER=\"%s\"\n", m_FontHover->m_Filename);
+
+ if (m_Cursor && m_Cursor->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", m_Cursor->m_Filename);
+
+ Buffer->PutTextIndent(Indent + 2, "HORIZONTAL=%s\n", m_Horizontal ? "TRUE" : "FALSE");
+
+ switch (m_Align) {
+ case TAL_LEFT:
+ Buffer->PutTextIndent(Indent + 2, "TEXT_ALIGN=\"%s\"\n", "left");
+ break;
+ case TAL_RIGHT:
+ Buffer->PutTextIndent(Indent + 2, "TEXT_ALIGN=\"%s\"\n", "right");
+ break;
+ case TAL_CENTER:
+ Buffer->PutTextIndent(Indent + 2, "TEXT_ALIGN=\"%s\"\n", "center");
+ break;
+ }
+
+ switch (m_VerticalAlign) {
+ case VAL_TOP:
+ Buffer->PutTextIndent(Indent + 2, "VERTICAL_ALIGN=\"%s\"\n", "top");
+ break;
+ case VAL_BOTTOM:
+ Buffer->PutTextIndent(Indent + 2, "VERTICAL_ALIGN=\"%s\"\n", "bottom");
+ break;
+ case VAL_CENTER:
+ Buffer->PutTextIndent(Indent + 2, "VERTICAL_ALIGN=\"%s\"\n", "center");
+ break;
+ }
+
+ Buffer->PutTextIndent(Indent + 2, "SPACING=%d\n", m_Spacing);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // window
+ if (m_Window) m_Window->SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // editor properties
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n");
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::Display() {
+ RECT rect = m_ResponseArea;
+ if (m_Window) {
+ CBPlatform::OffsetRect(&rect, m_Window->m_PosX, m_Window->m_PosY);
+ //m_Window->Display();
+ }
+
+ int xxx, yyy, i;
+
+ xxx = rect.left;
+ yyy = rect.top;
+
+ // shift down if needed
+ if (!m_Horizontal) {
+ int total_height = 0;
+ for (i = 0; i < m_RespButtons.GetSize(); i++) total_height += (m_RespButtons[i]->m_Height + m_Spacing);
+ total_height -= m_Spacing;
+
+ switch (m_VerticalAlign) {
+ case VAL_BOTTOM:
+ if (yyy + total_height < rect.bottom)
+ yyy = rect.bottom - total_height;
+ break;
+
+ case VAL_CENTER:
+ if (yyy + total_height < rect.bottom)
+ yyy += ((rect.bottom - rect.top) - total_height) / 2;
+ break;
+
+ case VAL_TOP:
+ // do nothing
+ break;
+ }
+ }
+
+ // prepare response buttons
+ bool scroll_needed = false;
+ for (i = m_ScrollOffset; i < m_RespButtons.GetSize(); i++) {
+ if ((m_Horizontal && xxx + m_RespButtons[i]->m_Width > rect.right)
+ || (!m_Horizontal && yyy + m_RespButtons[i]->m_Height > rect.bottom)) {
+
+ scroll_needed = true;
+ m_RespButtons[i]->m_Visible = false;
+ break;
+ }
+
+ m_RespButtons[i]->m_Visible = true;
+ m_RespButtons[i]->m_PosX = xxx;
+ m_RespButtons[i]->m_PosY = yyy;
+
+ if (m_Horizontal) {
+ xxx += (m_RespButtons[i]->m_Width + m_Spacing);
+ } else {
+ yyy += (m_RespButtons[i]->m_Height + m_Spacing);
+ }
+ }
+
+ // show appropriate scroll buttons
+ if (m_Window) {
+ m_Window->ShowWidget("prev", m_ScrollOffset > 0);
+ m_Window->ShowWidget("next", scroll_needed);
+ }
+
+ // go exclusive
+ if (m_ShieldWindow) {
+ m_ShieldWindow->m_PosX = m_ShieldWindow->m_PosY = 0;
+ m_ShieldWindow->m_Width = Game->m_Renderer->m_Width;
+ m_ShieldWindow->m_Height = Game->m_Renderer->m_Height;
+
+ m_ShieldWindow->Display();
+ }
+
+ // display window
+ if (m_Window) m_Window->Display();
+
+
+ // display response buttons
+ for (i = m_ScrollOffset; i < m_RespButtons.GetSize(); i++) {
+ m_RespButtons[i]->Display();
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::Listen(CBScriptHolder *param1, uint32 param2) {
+ CUIObject *obj = (CUIObject *)param1;
+
+ switch (obj->m_Type) {
+ case UI_BUTTON:
+ if (scumm_stricmp(obj->m_Name, "prev") == 0) {
+ m_ScrollOffset--;
+ } else if (scumm_stricmp(obj->m_Name, "next") == 0) {
+ m_ScrollOffset++;
+ } else if (scumm_stricmp(obj->m_Name, "response") == 0) {
+ if (m_WaitingScript) m_WaitingScript->m_Stack->PushInt(m_Responses[param2]->m_ID);
+ HandleResponse(m_Responses[param2]);
+ m_WaitingScript = NULL;
+ Game->m_State = GAME_RUNNING;
+ ((CAdGame *)Game)->m_StateEx = GAME_NORMAL;
+ m_Ready = true;
+ InvalidateButtons();
+ ClearResponses();
+ } else return CBObject::Listen(param1, param2);
+ break;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Font));
+ PersistMgr->Transfer(TMEMBER(m_FontHover));
+ PersistMgr->Transfer(TMEMBER(m_Horizontal));
+ PersistMgr->Transfer(TMEMBER(m_LastResponseText));
+ PersistMgr->Transfer(TMEMBER(m_LastResponseTextOrig));
+ m_RespButtons.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_ResponseArea));
+ m_Responses.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_ScrollOffset));
+ PersistMgr->Transfer(TMEMBER(m_ShieldWindow));
+ PersistMgr->Transfer(TMEMBER(m_Spacing));
+ PersistMgr->Transfer(TMEMBER(m_WaitingScript));
+ PersistMgr->Transfer(TMEMBER(m_Window));
+
+ PersistMgr->Transfer(TMEMBER_INT(m_VerticalAlign));
+ PersistMgr->Transfer(TMEMBER_INT(m_Align));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::WeedResponses() {
+ CAdGame *AdGame = (CAdGame *)Game;
+
+ for (int i = 0; i < m_Responses.GetSize(); i++) {
+ switch (m_Responses[i]->m_ResponseType) {
+ case RESPONSE_ONCE:
+ if (AdGame->BranchResponseUsed(m_Responses[i]->m_ID)) {
+ delete m_Responses[i];
+ m_Responses.RemoveAt(i);
+ i--;
+ }
+ break;
+
+ case RESPONSE_ONCE_GAME:
+ if (AdGame->GameResponseUsed(m_Responses[i]->m_ID)) {
+ delete m_Responses[i];
+ m_Responses.RemoveAt(i);
+ i--;
+ }
+ break;
+ }
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseBox::SetLastResponseText(char *Text, char *TextOrig) {
+ CBUtils::SetString(&m_LastResponseText, Text);
+ CBUtils::SetString(&m_LastResponseTextOrig, TextOrig);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::HandleResponse(CAdResponse *Response) {
+ SetLastResponseText(Response->m_Text, Response->m_TextOrig);
+
+ CAdGame *AdGame = (CAdGame *)Game;
+
+ switch (Response->m_ResponseType) {
+ case RESPONSE_ONCE:
+ AdGame->AddBranchResponse(Response->m_ID);
+ break;
+
+ case RESPONSE_ONCE_GAME:
+ AdGame->AddGameResponse(Response->m_ID);
+ break;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBObject *CAdResponseBox::GetNextAccessObject(CBObject *CurrObject) {
+ CBArray<CUIObject *, CUIObject *> Objects;
+ GetObjects(Objects, true);
+
+ if (Objects.GetSize() == 0) return NULL;
+ else {
+ if (CurrObject != NULL) {
+ for (int i = 0; i < Objects.GetSize(); i++) {
+ if (Objects[i] == CurrObject) {
+ if (i < Objects.GetSize() - 1) return Objects[i + 1];
+ else break;
+ }
+ }
+ }
+ return Objects[0];
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CBObject *CAdResponseBox::GetPrevAccessObject(CBObject *CurrObject) {
+ CBArray<CUIObject *, CUIObject *> Objects;
+ GetObjects(Objects, true);
+
+ if (Objects.GetSize() == 0) return NULL;
+ else {
+ if (CurrObject != NULL) {
+ for (int i = Objects.GetSize() - 1; i >= 0; i--) {
+ if (Objects[i] == CurrObject) {
+ if (i > 0) return Objects[i - 1];
+ else break;
+ }
+ }
+ }
+ return Objects[Objects.GetSize() - 1];
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::GetObjects(CBArray<CUIObject *, CUIObject *>& Objects, bool InteractiveOnly) {
+ for (int i = 0; i < m_RespButtons.GetSize(); i++) {
+ Objects.Add(m_RespButtons[i]);
+ }
+ if (m_Window) m_Window->GetWindowObjects(Objects, InteractiveOnly);
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdResponseBox.h b/engines/wintermute/AdResponseBox.h
new file mode 100644
index 0000000000..6abe9dc1a1
--- /dev/null
+++ b/engines/wintermute/AdResponseBox.h
@@ -0,0 +1,85 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdResponseBox_H__
+#define __WmeAdResponseBox_H__
+
+
+#include "BObject.h"
+
+namespace WinterMute {
+
+class CUIButton;
+class CUIWindow;
+class CUIObject;
+class CAdResponse;
+class CAdResponseBox : public CBObject {
+public:
+ CBObject *GetNextAccessObject(CBObject *CurrObject);
+ CBObject *GetPrevAccessObject(CBObject *CurrObject);
+ HRESULT GetObjects(CBArray<CUIObject *, CUIObject *>& Objects, bool InteractiveOnly);
+
+ HRESULT HandleResponse(CAdResponse *Response);
+ void SetLastResponseText(char *Text, char *TextOrig);
+ char *m_LastResponseText;
+ char *m_LastResponseTextOrig;
+ DECLARE_PERSISTENT(CAdResponseBox, CBObject)
+ CScScript *m_WaitingScript;
+ virtual HRESULT Listen(CBScriptHolder *param1, uint32 param2);
+ typedef enum {
+ EVENT_PREV, EVENT_NEXT, EVENT_RESPONSE
+ } TResponseEvent;
+
+ HRESULT WeedResponses();
+ HRESULT Display();
+ int m_Spacing;
+ int m_ScrollOffset;
+ CBFont *m_FontHover;
+ CBFont *m_Font;
+ HRESULT CreateButtons();
+ HRESULT InvalidateButtons();
+ void ClearButtons();
+ void ClearResponses();
+ CAdResponseBox(CBGame *inGame);
+ virtual ~CAdResponseBox();
+ CBArray<CAdResponse *, CAdResponse *> m_Responses;
+ CBArray<CUIButton *, CUIButton *> m_RespButtons;
+ CUIWindow *m_Window;
+ CUIWindow *m_ShieldWindow;
+ bool m_Horizontal;
+ RECT m_ResponseArea;
+ int m_VerticalAlign;
+ TTextAlign m_Align;
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdResponseContext.cpp b/engines/wintermute/AdResponseContext.cpp
new file mode 100644
index 0000000000..1e6fad4967
--- /dev/null
+++ b/engines/wintermute/AdResponseContext.cpp
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdResponseContext.h"
+#include "BPersistMgr.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdResponseContext, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseContext::CAdResponseContext(CBGame *inGame): CBBase(inGame) {
+ m_ID = 0;
+ m_Context = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseContext::~CAdResponseContext() {
+ delete[] m_Context;
+ m_Context = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseContext::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(Game));
+ PersistMgr->Transfer(TMEMBER(m_Context));
+ PersistMgr->Transfer(TMEMBER(m_ID));
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseContext::SetContext(char *Context) {
+ delete[] m_Context;
+ m_Context = NULL;
+ if (Context) {
+ m_Context = new char [strlen(Context) + 1];
+ if (m_Context) strcpy(m_Context, Context);
+ }
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdResponseContext.h b/engines/wintermute/AdResponseContext.h
new file mode 100644
index 0000000000..de3e8c95fa
--- /dev/null
+++ b/engines/wintermute/AdResponseContext.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdResponseContext_H__
+#define __WmeAdResponseContext_H__
+
+#include "persistent.h"
+#include "BBase.h"
+
+namespace WinterMute {
+
+class CAdResponseContext : public CBBase {
+public:
+ void SetContext(char *Context);
+ int m_ID;
+ char *m_Context;
+ DECLARE_PERSISTENT(CAdResponseContext, CBBase)
+ CAdResponseContext(CBGame *inGame);
+ virtual ~CAdResponseContext();
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdRotLevel.cpp b/engines/wintermute/AdRotLevel.cpp
new file mode 100644
index 0000000000..11bdb4dba0
--- /dev/null
+++ b/engines/wintermute/AdRotLevel.cpp
@@ -0,0 +1,159 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdRotLevel.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "BGame.h"
+#include "BSprite.h"
+#include "BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdRotLevel, false)
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdRotLevel::CAdRotLevel(CBGame *inGame): CBObject(inGame) {
+ m_PosX = 0;
+ m_Rotation = 0.0f;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdRotLevel::~CAdRotLevel() {
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRotLevel::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdRotLevel::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing ROTATION_LEVEL file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(ROTATION_LEVEL)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(X)
+TOKEN_DEF(ROTATION)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRotLevel::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ROTATION_LEVEL)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(ROTATION)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_ROTATION_LEVEL) {
+ Game->LOG(0, "'ROTATION_LEVEL' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_X:
+ parser.ScanStr((char *)params, "%d", &m_PosX);
+ break;
+
+ case TOKEN_ROTATION: {
+ int i;
+ parser.ScanStr((char *)params, "%d", &i);
+ m_Rotation = (float)i;
+ }
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in ROTATION_LEVEL definition");
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRotLevel::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "ROTATION_LEVEL {\n");
+ Buffer->PutTextIndent(Indent + 2, "X=%d\n", m_PosX);
+ Buffer->PutTextIndent(Indent + 2, "ROTATION=%d\n", (int)m_Rotation);
+ CBBase::SaveAsText(Buffer, Indent + 2);
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRotLevel::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Rotation));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdRotLevel.h b/engines/wintermute/AdRotLevel.h
new file mode 100644
index 0000000000..91ddbef641
--- /dev/null
+++ b/engines/wintermute/AdRotLevel.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdRotLevel_H__
+#define __WmeAdRotLevel_H__
+
+#include "BObject.h"
+
+namespace WinterMute {
+
+class CAdRotLevel : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdRotLevel, CBObject)
+ CAdRotLevel(CBGame *inGame);
+ virtual ~CAdRotLevel();
+ float m_Rotation;
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdScaleLevel.cpp b/engines/wintermute/AdScaleLevel.cpp
new file mode 100644
index 0000000000..09c4a78062
--- /dev/null
+++ b/engines/wintermute/AdScaleLevel.cpp
@@ -0,0 +1,157 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdScaleLevel.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "BGame.h"
+#include "BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdScaleLevel, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdScaleLevel::CAdScaleLevel(CBGame *inGame): CBObject(inGame) {
+ m_PosY = 0;
+ m_Scale = 100;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdScaleLevel::~CAdScaleLevel() {
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScaleLevel::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdScaleLevel::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing SCALE_LEVEL file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(SCALE_LEVEL)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(Y)
+TOKEN_DEF(SCALE)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScaleLevel::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(SCALE_LEVEL)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(SCALE)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_SCALE_LEVEL) {
+ Game->LOG(0, "'SCALE_LEVEL' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_Y:
+ parser.ScanStr((char *)params, "%d", &m_PosY);
+ break;
+
+ case TOKEN_SCALE: {
+ int i;
+ parser.ScanStr((char *)params, "%d", &i);
+ m_Scale = (float)i;
+ }
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in SCALE_LEVEL definition");
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScaleLevel::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "SCALE_LEVEL {\n");
+ Buffer->PutTextIndent(Indent + 2, "Y=%d\n", m_PosY);
+ Buffer->PutTextIndent(Indent + 2, "SCALE=%d\n", (int)m_Scale);
+ CBBase::SaveAsText(Buffer, Indent + 2);
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScaleLevel::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Scale));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdScaleLevel.h b/engines/wintermute/AdScaleLevel.h
new file mode 100644
index 0000000000..5fe1cafa6b
--- /dev/null
+++ b/engines/wintermute/AdScaleLevel.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdScaleLevel_H__
+#define __WmeAdScaleLevel_H__
+
+
+#include "BObject.h"
+
+namespace WinterMute {
+
+class CAdScaleLevel : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdScaleLevel, CBObject)
+ float m_Scale;
+ CAdScaleLevel(CBGame *inGame);
+ virtual ~CAdScaleLevel();
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdScene.cpp b/engines/wintermute/AdScene.cpp
new file mode 100644
index 0000000000..3fb13f5d61
--- /dev/null
+++ b/engines/wintermute/AdScene.cpp
@@ -0,0 +1,2760 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "AdScene.h"
+#include "AdActor.h"
+#include "AdEntity.h"
+#include "AdGame.h"
+#include "AdLayer.h"
+#include "AdNodeState.h"
+#include "AdObject.h"
+#include "AdPath.h"
+#include "AdPathPoint.h"
+#include "AdRotLevel.h"
+#include "AdScaleLevel.h"
+#include "AdSceneNode.h"
+#include "AdSceneState.h"
+#include "AdSentence.h"
+#include "AdWaypointGroup.h"
+#include "BDynBuffer.h"
+#include "BFileManager.h"
+#include "BFont.h"
+#include "BGame.h"
+#include "BObject.h"
+#include "BParser.h"
+#include "BPoint.h"
+#include "BRegion.h"
+#include "BScriptable.h"
+#include "BSprite.h"
+#include "BViewport.h"
+#include "PlatformSDL.h"
+#include "ScStack.h"
+#include "ScValue.h"
+#include "ScScript.h"
+#include "UIWindow.h"
+#include "utils.h"
+#include <math.h>
+#include <limits.h>
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdScene, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdScene::CAdScene(CBGame *inGame): CBObject(inGame) {
+ m_PFTarget = new CBPoint;
+ SetDefaults();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdScene::~CAdScene() {
+ Cleanup();
+ Game->UnregisterObject(m_Fader);
+ delete m_PFTarget;
+ m_PFTarget = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::SetDefaults() {
+ m_Initialized = false;
+ m_PFReady = true;
+ m_PFTargetPath = NULL;
+ m_PFRequester = NULL;
+ m_MainLayer = NULL;
+
+ m_PFPointsNum = 0;
+ m_PersistentState = false;
+ m_PersistentStateSprites = true;
+
+ m_AutoScroll = true;
+ m_OffsetLeft = m_OffsetTop = 0;
+ m_TargetOffsetLeft = m_TargetOffsetTop = 0;
+
+ m_LastTimeH = m_LastTimeV = 0;
+ m_ScrollTimeH = m_ScrollTimeV = 10;
+ m_ScrollPixelsH = m_ScrollPixelsV = 1;
+
+ m_PFMaxTime = 15;
+
+ m_ParalaxScrolling = true;
+
+ // editor settings
+ m_EditorMarginH = m_EditorMarginV = 100;
+
+ m_EditorColFrame = 0xE0888888;
+ m_EditorColEntity = 0xFF008000;
+ m_EditorColRegion = 0xFF0000FF;
+ m_EditorColBlocked = 0xFF800080;
+ m_EditorColWaypoints = 0xFF0000FF;
+ m_EditorColEntitySel = 0xFFFF0000;
+ m_EditorColRegionSel = 0xFFFF0000;
+ m_EditorColBlockedSel = 0xFFFF0000;
+ m_EditorColWaypointsSel = 0xFFFF0000;
+ m_EditorColScale = 0xFF00FF00;
+ m_EditorColDecor = 0xFF00FFFF;
+ m_EditorColDecorSel = 0xFFFF0000;
+
+ m_EditorShowRegions = true;
+ m_EditorShowBlocked = true;
+ m_EditorShowDecor = true;
+ m_EditorShowEntities = true;
+ m_EditorShowScale = true;
+
+ m_ShieldWindow = NULL;
+
+ m_Fader = new CBFader(Game);
+ Game->RegisterObject(m_Fader);
+
+ m_Viewport = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::Cleanup() {
+ CBObject::Cleanup();
+
+ m_MainLayer = NULL; // reference only
+
+ int i;
+
+ delete m_ShieldWindow;
+ m_ShieldWindow = NULL;
+
+ Game->UnregisterObject(m_Fader);
+ m_Fader = NULL;
+
+ for (i = 0; i < m_Layers.GetSize(); i++)
+ Game->UnregisterObject(m_Layers[i]);
+ m_Layers.RemoveAll();
+
+
+ for (i = 0; i < m_WaypointGroups.GetSize(); i++)
+ Game->UnregisterObject(m_WaypointGroups[i]);
+ m_WaypointGroups.RemoveAll();
+
+ for (i = 0; i < m_ScaleLevels.GetSize(); i++)
+ Game->UnregisterObject(m_ScaleLevels[i]);
+ m_ScaleLevels.RemoveAll();
+
+ for (i = 0; i < m_RotLevels.GetSize(); i++)
+ Game->UnregisterObject(m_RotLevels[i]);
+ m_RotLevels.RemoveAll();
+
+
+ for (i = 0; i < m_PFPath.GetSize(); i++)
+ delete m_PFPath[i];
+ m_PFPath.RemoveAll();
+ m_PFPointsNum = 0;
+
+ for (i = 0; i < m_Objects.GetSize(); i++)
+ Game->UnregisterObject(m_Objects[i]);
+ m_Objects.RemoveAll();
+
+ delete m_Viewport;
+ m_Viewport = NULL;
+
+ SetDefaults();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdScene::GetPath(CBPoint source, CBPoint target, CAdPath *path, CBObject *requester) {
+ if (!m_PFReady) return false;
+ else {
+ m_PFReady = false;
+ *m_PFTarget = target;
+ m_PFTargetPath = path;
+ m_PFRequester = requester;
+
+ m_PFTargetPath->Reset();
+ m_PFTargetPath->SetReady(false);
+
+ // prepare working path
+ int i;
+ PFPointsStart();
+
+ // first point
+ //m_PFPath.Add(new CAdPathPoint(source.x, source.y, 0));
+
+ // if we're one pixel stuck, get unstuck
+ int StartX = source.x;
+ int StartY = source.y;
+ int BestDistance = 1000;
+ if (IsBlockedAt(StartX, StartY, true, requester)) {
+ int Tolerance = 2;
+ for (int xxx = StartX - Tolerance; xxx <= StartX + Tolerance; xxx++) {
+ for (int yyy = StartY - Tolerance; yyy <= StartY + Tolerance; yyy++) {
+ if (IsWalkableAt(xxx, yyy, true, requester)) {
+ int Distance = abs(xxx - source.x) + abs(yyy - source.y);
+ if (Distance < BestDistance) {
+ StartX = xxx;
+ StartY = yyy;
+
+ BestDistance = Distance;
+ }
+ }
+ }
+ }
+ }
+
+ PFPointsAdd(StartX, StartY, 0);
+
+ //CorrectTargetPoint(&target.x, &target.y);
+
+ // last point
+ //m_PFPath.Add(new CAdPathPoint(target.x, target.y, INT_MAX));
+ PFPointsAdd(target.x, target.y, INT_MAX);
+
+ // active waypoints
+ for (i = 0; i < m_WaypointGroups.GetSize(); i++) {
+ if (m_WaypointGroups[i]->m_Active) {
+ PFAddWaypointGroup(m_WaypointGroups[i], requester);
+ }
+ }
+
+
+ // free waypoints
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Active && m_Objects[i] != requester && m_Objects[i]->m_CurrentWptGroup) {
+ PFAddWaypointGroup(m_Objects[i]->m_CurrentWptGroup, requester);
+ }
+ }
+ CAdGame *AdGame = (CAdGame *)Game;
+ for (i = 0; i < AdGame->m_Objects.GetSize(); i++) {
+ if (AdGame->m_Objects[i]->m_Active && AdGame->m_Objects[i] != requester && AdGame->m_Objects[i]->m_CurrentWptGroup) {
+ PFAddWaypointGroup(AdGame->m_Objects[i]->m_CurrentWptGroup, requester);
+ }
+ }
+
+ return true;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::PFAddWaypointGroup(CAdWaypointGroup *Wpt, CBObject *Requester) {
+ if (!Wpt->m_Active) return;
+
+ for (int i = 0; i < Wpt->m_Points.GetSize(); i++) {
+ if (IsBlockedAt(Wpt->m_Points[i]->x, Wpt->m_Points[i]->y, true, Requester)) continue;
+
+ //m_PFPath.Add(new CAdPathPoint(Wpt->m_Points[i]->x, Wpt->m_Points[i]->y, INT_MAX));
+ PFPointsAdd(Wpt->m_Points[i]->x, Wpt->m_Points[i]->y, INT_MAX);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+float CAdScene::GetZoomAt(int X, int Y) {
+ float ret = 100;
+
+ bool found = false;
+ if (m_MainLayer) {
+ for (int i = m_MainLayer->m_Nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = m_MainLayer->m_Nodes[i];
+ if (Node->m_Type == OBJECT_REGION && Node->m_Region->m_Active && !Node->m_Region->m_Blocked && Node->m_Region->PointInRegion(X, Y)) {
+ if (Node->m_Region->m_Zoom != 0) {
+ ret = Node->m_Region->m_Zoom;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!found) ret = GetScaleAt(Y);
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CAdScene::GetAlphaAt(int X, int Y, bool ColorCheck) {
+ if (!Game->m_DEBUG_DebugMode) ColorCheck = false;
+
+ uint32 ret;
+ if (ColorCheck) ret = 0xFFFF0000;
+ else ret = 0xFFFFFFFF;
+
+ if (m_MainLayer) {
+ for (int i = m_MainLayer->m_Nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = m_MainLayer->m_Nodes[i];
+ if (Node->m_Type == OBJECT_REGION && Node->m_Region->m_Active && (ColorCheck || !Node->m_Region->m_Blocked) && Node->m_Region->PointInRegion(X, Y)) {
+ if (!Node->m_Region->m_Blocked) ret = Node->m_Region->m_Alpha;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdScene::IsBlockedAt(int X, int Y, bool CheckFreeObjects, CBObject *Requester) {
+ bool ret = true;
+
+
+ if (CheckFreeObjects) {
+ int i;
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Active && m_Objects[i] != Requester && m_Objects[i]->m_CurrentBlockRegion) {
+ if (m_Objects[i]->m_CurrentBlockRegion->PointInRegion(X, Y)) return true;
+ }
+ }
+ CAdGame *AdGame = (CAdGame *)Game;
+ for (i = 0; i < AdGame->m_Objects.GetSize(); i++) {
+ if (AdGame->m_Objects[i]->m_Active && AdGame->m_Objects[i] != Requester && AdGame->m_Objects[i]->m_CurrentBlockRegion) {
+ if (AdGame->m_Objects[i]->m_CurrentBlockRegion->PointInRegion(X, Y)) return true;
+ }
+ }
+ }
+
+
+ if (m_MainLayer) {
+ for (int i = 0; i < m_MainLayer->m_Nodes.GetSize(); i++) {
+ CAdSceneNode *Node = m_MainLayer->m_Nodes[i];
+ /*
+ if(Node->m_Type == OBJECT_REGION && Node->m_Region->m_Active && Node->m_Region->m_Blocked && Node->m_Region->PointInRegion(X, Y))
+ {
+ ret = true;
+ break;
+ }
+ */
+ if (Node->m_Type == OBJECT_REGION && Node->m_Region->m_Active && !Node->m_Region->m_Decoration && Node->m_Region->PointInRegion(X, Y)) {
+ if (Node->m_Region->m_Blocked) {
+ ret = true;
+ break;
+ } else ret = false;
+ }
+ }
+ }
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdScene::IsWalkableAt(int X, int Y, bool CheckFreeObjects, CBObject *Requester) {
+ bool ret = false;
+
+
+ if (CheckFreeObjects) {
+ int i;
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Active && m_Objects[i] != Requester && m_Objects[i]->m_CurrentBlockRegion) {
+ if (m_Objects[i]->m_CurrentBlockRegion->PointInRegion(X, Y)) return false;
+ }
+ }
+ CAdGame *AdGame = (CAdGame *)Game;
+ for (i = 0; i < AdGame->m_Objects.GetSize(); i++) {
+ if (AdGame->m_Objects[i]->m_Active && AdGame->m_Objects[i] != Requester && AdGame->m_Objects[i]->m_CurrentBlockRegion) {
+ if (AdGame->m_Objects[i]->m_CurrentBlockRegion->PointInRegion(X, Y)) return false;
+ }
+ }
+ }
+
+
+ if (m_MainLayer) {
+ for (int i = 0; i < m_MainLayer->m_Nodes.GetSize(); i++) {
+ CAdSceneNode *Node = m_MainLayer->m_Nodes[i];
+ if (Node->m_Type == OBJECT_REGION && Node->m_Region->m_Active && !Node->m_Region->m_Decoration && Node->m_Region->PointInRegion(X, Y)) {
+ if (Node->m_Region->m_Blocked) {
+ ret = false;
+ break;
+ } else ret = true;
+ }
+ }
+ }
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdScene::GetPointsDist(CBPoint p1, CBPoint p2, CBObject *requester) {
+ double xStep, yStep, X, Y;
+ int xLength, yLength, xCount, yCount;
+ int X1, Y1, X2, Y2;
+
+ X1 = p1.x;
+ Y1 = p1.y;
+ X2 = p2.x;
+ Y2 = p2.y;
+
+ xLength = abs(X2 - X1);
+ yLength = abs(Y2 - Y1);
+
+ if (xLength > yLength) {
+ if (X1 > X2) {
+ CBUtils::Swap(&X1, &X2);
+ CBUtils::Swap(&Y1, &Y2);
+ }
+
+ yStep = (double)(Y2 - Y1) / (double)(X2 - X1);
+ Y = Y1;
+
+ for (xCount = X1; xCount < X2; xCount++) {
+ if (IsBlockedAt(xCount, (int)Y, true, requester)) return -1;
+ Y += yStep;
+ }
+ } else {
+ if (Y1 > Y2) {
+ CBUtils::Swap(&X1, &X2);
+ CBUtils::Swap(&Y1, &Y2);
+ }
+
+ xStep = (double)(X2 - X1) / (double)(Y2 - Y1);
+ X = X1;
+
+ for (yCount = Y1; yCount < Y2; yCount++) {
+ if (IsBlockedAt((int)X, yCount, true, requester)) return -1;
+ X += xStep;
+ }
+ }
+ return std::max(xLength, yLength);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::PathFinderStep() {
+ int i;
+ // get lowest unmarked
+ int lowest_dist = INT_MAX;
+ CAdPathPoint *lowest_pt = NULL;
+
+ for (i = 0; i < m_PFPointsNum; i++)
+ if (!m_PFPath[i]->m_Marked && m_PFPath[i]->m_Distance < lowest_dist) {
+ lowest_dist = m_PFPath[i]->m_Distance;
+ lowest_pt = m_PFPath[i];
+ }
+
+ if (lowest_pt == NULL) { // no path -> terminate PathFinder
+ m_PFReady = true;
+ m_PFTargetPath->SetReady(true);
+ return;
+ }
+
+ lowest_pt->m_Marked = true;
+
+ // target point marked, generate path and terminate
+ if (lowest_pt->x == m_PFTarget->x && lowest_pt->y == m_PFTarget->y) {
+ while (lowest_pt != NULL) {
+ m_PFTargetPath->m_Points.InsertAt(0, new CBPoint(lowest_pt->x, lowest_pt->y));
+ lowest_pt = lowest_pt->m_Origin;
+ }
+
+ m_PFReady = true;
+ m_PFTargetPath->SetReady(true);
+ return;
+ }
+
+ // otherwise keep on searching
+ for (i = 0; i < m_PFPointsNum; i++)
+ if (!m_PFPath[i]->m_Marked) {
+ int j = GetPointsDist(*lowest_pt, *m_PFPath[i], m_PFRequester);
+ if (j != -1 && lowest_pt->m_Distance + j < m_PFPath[i]->m_Distance) {
+ m_PFPath[i]->m_Distance = lowest_pt->m_Distance + j;
+ m_PFPath[i]->m_Origin = lowest_pt;
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::InitLoop() {
+#ifdef _DEBUGxxxx
+ int num_steps = 0;
+ uint32 start = Game->m_CurrentTime;
+ while (!m_PFReady && CBPlatform::GetTime() - start <= m_PFMaxTime) {
+ PathFinderStep();
+ num_steps++;
+ }
+ if (num_steps > 0) Game->LOG(0, "STAT: PathFinder iterations in one loop: %d (%s) m_PFMaxTime=%d", num_steps, m_PFReady ? "finished" : "not yet done", m_PFMaxTime);
+#else
+ uint32 start = Game->m_CurrentTime;
+ while (!m_PFReady && CBPlatform::GetTime() - start <= m_PFMaxTime) PathFinderStep();
+#endif
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdScene::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ delete[] m_Filename;
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing SCENE file '%s'", Filename);
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(SCENE)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(NAME)
+TOKEN_DEF(LAYER)
+TOKEN_DEF(WAYPOINTS)
+TOKEN_DEF(EVENTS)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(CAMERA)
+TOKEN_DEF(ENTITY)
+TOKEN_DEF(SCALE_LEVEL)
+TOKEN_DEF(ROTATION_LEVEL)
+TOKEN_DEF(EDITOR_MARGIN_H)
+TOKEN_DEF(EDITOR_MARGIN_V)
+TOKEN_DEF(EDITOR_COLOR_FRAME)
+TOKEN_DEF(EDITOR_COLOR_ENTITY_SEL)
+TOKEN_DEF(EDITOR_COLOR_REGION_SEL)
+TOKEN_DEF(EDITOR_COLOR_DECORATION_SEL)
+TOKEN_DEF(EDITOR_COLOR_BLOCKED_SEL)
+TOKEN_DEF(EDITOR_COLOR_WAYPOINTS_SEL)
+TOKEN_DEF(EDITOR_COLOR_REGION)
+TOKEN_DEF(EDITOR_COLOR_DECORATION)
+TOKEN_DEF(EDITOR_COLOR_BLOCKED)
+TOKEN_DEF(EDITOR_COLOR_ENTITY)
+TOKEN_DEF(EDITOR_COLOR_WAYPOINTS)
+TOKEN_DEF(EDITOR_COLOR_SCALE)
+TOKEN_DEF(EDITOR_SHOW_REGIONS)
+TOKEN_DEF(EDITOR_SHOW_BLOCKED)
+TOKEN_DEF(EDITOR_SHOW_DECORATION)
+TOKEN_DEF(EDITOR_SHOW_ENTITIES)
+TOKEN_DEF(EDITOR_SHOW_SCALE)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PROPERTY)
+TOKEN_DEF(VIEWPORT)
+TOKEN_DEF(PERSISTENT_STATE_SPRITES)
+TOKEN_DEF(PERSISTENT_STATE)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(SCENE)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(LAYER)
+ TOKEN_TABLE(WAYPOINTS)
+ TOKEN_TABLE(EVENTS)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(CAMERA)
+ TOKEN_TABLE(ENTITY)
+ TOKEN_TABLE(SCALE_LEVEL)
+ TOKEN_TABLE(ROTATION_LEVEL)
+ TOKEN_TABLE(EDITOR_MARGIN_H)
+ TOKEN_TABLE(EDITOR_MARGIN_V)
+ TOKEN_TABLE(EDITOR_COLOR_FRAME)
+ TOKEN_TABLE(EDITOR_COLOR_ENTITY_SEL)
+ TOKEN_TABLE(EDITOR_COLOR_REGION_SEL)
+ TOKEN_TABLE(EDITOR_COLOR_DECORATION_SEL)
+ TOKEN_TABLE(EDITOR_COLOR_BLOCKED_SEL)
+ TOKEN_TABLE(EDITOR_COLOR_WAYPOINTS_SEL)
+ TOKEN_TABLE(EDITOR_COLOR_REGION)
+ TOKEN_TABLE(EDITOR_COLOR_DECORATION)
+ TOKEN_TABLE(EDITOR_COLOR_BLOCKED)
+ TOKEN_TABLE(EDITOR_COLOR_ENTITY)
+ TOKEN_TABLE(EDITOR_COLOR_WAYPOINTS)
+ TOKEN_TABLE(EDITOR_COLOR_SCALE)
+ TOKEN_TABLE(EDITOR_SHOW_REGIONS)
+ TOKEN_TABLE(EDITOR_SHOW_DECORATION)
+ TOKEN_TABLE(EDITOR_SHOW_BLOCKED)
+ TOKEN_TABLE(EDITOR_SHOW_ENTITIES)
+ TOKEN_TABLE(EDITOR_SHOW_SCALE)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PROPERTY)
+ TOKEN_TABLE(VIEWPORT)
+ TOKEN_TABLE(PERSISTENT_STATE_SPRITES)
+ TOKEN_TABLE(PERSISTENT_STATE)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ Cleanup();
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_SCENE) {
+ Game->LOG(0, "'SCENE' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ int ar, ag, ab, aa;
+ char camera[MAX_PATH] = "";
+ float WaypointHeight = -1.0f;
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ SetCaption((char *)params);
+ break;
+
+ case TOKEN_LAYER: {
+ CAdLayer *layer = new CAdLayer(Game);
+ if (!layer || FAILED(layer->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ delete layer;
+ layer = NULL;
+ } else {
+ Game->RegisterObject(layer);
+ m_Layers.Add(layer);
+ if (layer->m_Main) {
+ m_MainLayer = layer;
+ m_Width = layer->m_Width;
+ m_Height = layer->m_Height;
+ }
+ }
+ }
+ break;
+
+ case TOKEN_WAYPOINTS: {
+ CAdWaypointGroup *wpt = new CAdWaypointGroup(Game);
+ if (!wpt || FAILED(wpt->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ delete wpt;
+ wpt = NULL;
+ } else {
+ Game->RegisterObject(wpt);
+ m_WaypointGroups.Add(wpt);
+ }
+ }
+ break;
+
+ case TOKEN_SCALE_LEVEL: {
+ CAdScaleLevel *sl = new CAdScaleLevel(Game);
+ if (!sl || FAILED(sl->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ delete sl;
+ sl = NULL;
+ } else {
+ Game->RegisterObject(sl);
+ m_ScaleLevels.Add(sl);
+ }
+ }
+ break;
+
+ case TOKEN_ROTATION_LEVEL: {
+ CAdRotLevel *rl = new CAdRotLevel(Game);
+ if (!rl || FAILED(rl->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ delete rl;
+ rl = NULL;
+ } else {
+ Game->RegisterObject(rl);
+ m_RotLevels.Add(rl);
+ }
+ }
+ break;
+
+ case TOKEN_ENTITY: {
+ CAdEntity *entity = new CAdEntity(Game);
+ if (!entity || FAILED(entity->LoadBuffer(params, false))) {
+ cmd = PARSERR_GENERIC;
+ delete entity;
+ entity = NULL;
+ } else {
+ AddObject(entity);
+ }
+ }
+ break;
+
+ case TOKEN_CURSOR:
+ delete m_Cursor;
+ m_Cursor = new CBSprite(Game);
+ if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) {
+ delete m_Cursor;
+ m_Cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_CAMERA:
+ strcpy(camera, (char *)params);
+ break;
+
+ case TOKEN_EDITOR_MARGIN_H:
+ parser.ScanStr((char *)params, "%d", &m_EditorMarginH);
+ break;
+
+ case TOKEN_EDITOR_MARGIN_V:
+ parser.ScanStr((char *)params, "%d", &m_EditorMarginV);
+ break;
+
+ case TOKEN_EDITOR_COLOR_FRAME:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColFrame = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_ENTITY:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColEntity = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_ENTITY_SEL:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColEntitySel = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_REGION_SEL:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColRegionSel = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_DECORATION_SEL:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColDecorSel = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_BLOCKED_SEL:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColBlockedSel = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_WAYPOINTS_SEL:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColWaypointsSel = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_REGION:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColRegion = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_DECORATION:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColDecor = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_BLOCKED:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColBlocked = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_WAYPOINTS:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColWaypoints = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_SCALE:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ m_EditorColScale = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_SHOW_REGIONS:
+ parser.ScanStr((char *)params, "%b", &m_EditorShowRegions);
+ break;
+
+ case TOKEN_EDITOR_SHOW_BLOCKED:
+ parser.ScanStr((char *)params, "%b", &m_EditorShowBlocked);
+ break;
+
+ case TOKEN_EDITOR_SHOW_DECORATION:
+ parser.ScanStr((char *)params, "%b", &m_EditorShowDecor);
+ break;
+
+ case TOKEN_EDITOR_SHOW_ENTITIES:
+ parser.ScanStr((char *)params, "%b", &m_EditorShowEntities);
+ break;
+
+ case TOKEN_EDITOR_SHOW_SCALE:
+ parser.ScanStr((char *)params, "%b", &m_EditorShowScale);
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_VIEWPORT: {
+ RECT rc;
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &rc.left, &rc.top, &rc.right, &rc.bottom);
+ if (!m_Viewport) m_Viewport = new CBViewport(Game);
+ if (m_Viewport) m_Viewport->SetRect(rc.left, rc.top, rc.right, rc.bottom, true);
+ }
+
+ case TOKEN_PERSISTENT_STATE:
+ parser.ScanStr((char *)params, "%b", &m_PersistentState);
+ break;
+
+ case TOKEN_PERSISTENT_STATE_SPRITES:
+ parser.ScanStr((char *)params, "%b", &m_PersistentStateSprites);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in SCENE definition");
+ return E_FAIL;
+ }
+
+ if (m_MainLayer == NULL) Game->LOG(0, "Warning: scene '%s' has no main layer.", m_Filename);
+
+
+ SortScaleLevels();
+ SortRotLevels();
+
+ m_Initialized = true;
+
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::TraverseNodes(bool Update) {
+ if (!m_Initialized) return S_OK;
+
+ int j, k;
+ CAdGame *AdGame = (CAdGame *)Game;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // prepare viewport
+ bool PopViewport = false;
+ if (m_Viewport && !Game->m_EditorMode) {
+ Game->PushViewport(m_Viewport);
+ PopViewport = true;
+ } else if (AdGame->m_SceneViewport && !Game->m_EditorMode) {
+ Game->PushViewport(AdGame->m_SceneViewport);
+ PopViewport = true;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // *** adjust scroll offset
+ if (Update) {
+ /*
+ if(m_AutoScroll && Game->m_MainObject != NULL)
+ {
+ ScrollToObject(Game->m_MainObject);
+ }
+ */
+
+ if (m_AutoScroll) {
+ // adjust horizontal scroll
+ if (Game->m_Timer - m_LastTimeH >= m_ScrollTimeH) {
+ m_LastTimeH = Game->m_Timer;
+ if (m_OffsetLeft < m_TargetOffsetLeft) {
+ m_OffsetLeft += m_ScrollPixelsH;
+ m_OffsetLeft = std::min(m_OffsetLeft, m_TargetOffsetLeft);
+ } else if (m_OffsetLeft > m_TargetOffsetLeft) {
+ m_OffsetLeft -= m_ScrollPixelsH;
+ m_OffsetLeft = std::max(m_OffsetLeft, m_TargetOffsetLeft);
+ }
+ }
+
+ // adjust vertical scroll
+ if (Game->m_Timer - m_LastTimeV >= m_ScrollTimeV) {
+ m_LastTimeV = Game->m_Timer;
+ if (m_OffsetTop < m_TargetOffsetTop) {
+ m_OffsetTop += m_ScrollPixelsV;
+ m_OffsetTop = std::min(m_OffsetTop, m_TargetOffsetTop);
+ } else if (m_OffsetTop > m_TargetOffsetTop) {
+ m_OffsetTop -= m_ScrollPixelsV;
+ m_OffsetTop = std::max(m_OffsetTop, m_TargetOffsetTop);
+ }
+ }
+
+ if (m_OffsetTop == m_TargetOffsetTop && m_OffsetLeft == m_TargetOffsetLeft) m_Ready = true;
+ } else m_Ready = true; // not scrolling, i.e. always ready
+ }
+
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ int ViewportX, ViewportY;
+ GetViewportOffset(&ViewportX, &ViewportY);
+
+ int ScrollableX = m_Width - ViewportWidth;
+ int ScrollableY = m_Height - ViewportHeight;
+
+ double WidthRatio = ScrollableX <= 0 ? 0 : ((double)(m_OffsetLeft) / (double)ScrollableX);
+ double HeightRatio = ScrollableY <= 0 ? 0 : ((double)(m_OffsetTop) / (double)ScrollableY);
+
+ int OrigX, OrigY;
+ Game->GetOffset(&OrigX, &OrigY);
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // *** display/update everything
+ Game->m_Renderer->Setup2D();
+
+ // for each layer
+ int MainOffsetX = 0;
+ int MainOffsetY = 0;
+
+ for (j = 0; j < m_Layers.GetSize(); j++) {
+ if (!m_Layers[j]->m_Active) continue;
+
+ // make layer exclusive
+ if (!Update) {
+ if (m_Layers[j]->m_CloseUp && !Game->m_EditorMode) {
+ if (!m_ShieldWindow) m_ShieldWindow = new CUIWindow(Game);
+ if (m_ShieldWindow) {
+ m_ShieldWindow->m_PosX = m_ShieldWindow->m_PosY = 0;
+ m_ShieldWindow->m_Width = Game->m_Renderer->m_Width;
+ m_ShieldWindow->m_Height = Game->m_Renderer->m_Height;
+ m_ShieldWindow->Display();
+ }
+ }
+ }
+
+ if (m_ParalaxScrolling) {
+ int OffsetX = (int)(WidthRatio * (m_Layers[j]->m_Width - ViewportWidth) - ViewportX);
+ int OffsetY = (int)(HeightRatio * (m_Layers[j]->m_Height - ViewportHeight) - ViewportY);
+ Game->SetOffset(OffsetX, OffsetY);
+
+ Game->m_OffsetPercentX = (float)OffsetX / ((float)m_Layers[j]->m_Width - ViewportWidth) * 100.0f;
+ Game->m_OffsetPercentY = (float)OffsetY / ((float)m_Layers[j]->m_Height - ViewportHeight) * 100.0f;
+
+ //Game->QuickMessageForm("%d %f", OffsetX+ViewportX, Game->m_OffsetPercentX);
+ } else {
+ Game->SetOffset(m_OffsetLeft - ViewportX, m_OffsetTop - ViewportY);
+
+ Game->m_OffsetPercentX = (float)(m_OffsetLeft - ViewportX) / ((float)m_Layers[j]->m_Width - ViewportWidth) * 100.0f;
+ Game->m_OffsetPercentY = (float)(m_OffsetTop - ViewportY) / ((float)m_Layers[j]->m_Height - ViewportHeight) * 100.0f;
+ }
+
+
+ // for each node
+ for (k = 0; k < m_Layers[j]->m_Nodes.GetSize(); k++) {
+ CAdSceneNode *Node = m_Layers[j]->m_Nodes[k];
+ switch (Node->m_Type) {
+ case OBJECT_ENTITY:
+ if (Node->m_Entity->m_Active && (Game->m_EditorMode || !Node->m_Entity->m_EditorOnly)) {
+ Game->m_Renderer->Setup2D();
+
+ if (Update) Node->m_Entity->Update();
+ else Node->m_Entity->Display();
+ }
+ break;
+
+ case OBJECT_REGION: {
+ if (Node->m_Region->m_Blocked) break;
+ if (Node->m_Region->m_Decoration) break;
+
+ if (!Update) DisplayRegionContent(Node->m_Region);
+ }
+ break;
+ } // switch
+ } // each node
+
+ // display/update all objects which are off-regions
+ if (m_Layers[j]->m_Main) {
+ if (Update) {
+ UpdateFreeObjects();
+ } else {
+ DisplayRegionContent(NULL);
+ }
+ }
+ } // each layer
+
+
+ // restore state
+ Game->SetOffset(OrigX, OrigY);
+ Game->m_Renderer->Setup2D();
+
+ // display/update fader
+ if (m_Fader) {
+ if (Update) m_Fader->Update();
+ else m_Fader->Display();
+ }
+
+ if (PopViewport) Game->PopViewport();
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::Display() {
+ return TraverseNodes(false);
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::UpdateFreeObjects() {
+ CAdGame *AdGame = (CAdGame *)Game;
+ int i;
+
+ bool Is3DSet;
+
+ // *** update all active objects
+ Is3DSet = false;
+ for (i = 0; i < AdGame->m_Objects.GetSize(); i++) {
+ if (!AdGame->m_Objects[i]->m_Active) continue;
+
+ AdGame->m_Objects[i]->Update();
+ AdGame->m_Objects[i]->m_Drawn = false;
+ }
+
+
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (!m_Objects[i]->m_Active) continue;
+
+ m_Objects[i]->Update();
+ m_Objects[i]->m_Drawn = false;
+ }
+
+
+ if (m_AutoScroll && Game->m_MainObject != NULL) {
+ ScrollToObject(Game->m_MainObject);
+ }
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::DisplayRegionContent(CAdRegion *Region, bool Display3DOnly) {
+ CAdGame *AdGame = (CAdGame *)Game;
+ CBArray<CAdObject *, CAdObject *> Objects;
+ CAdObject *Obj;
+
+ int i;
+
+ // global objects
+ for (i = 0; i < AdGame->m_Objects.GetSize(); i++) {
+ Obj = AdGame->m_Objects[i];
+ if (Obj->m_Active && !Obj->m_Drawn && (Obj->m_StickRegion == Region || Region == NULL || (Obj->m_StickRegion == NULL && Region->PointInRegion(Obj->m_PosX, Obj->m_PosY)))) {
+ Objects.Add(Obj);
+ }
+ }
+
+ // scene objects
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ Obj = m_Objects[i];
+ if (Obj->m_Active && !Obj->m_EditorOnly && !Obj->m_Drawn && (Obj->m_StickRegion == Region || Region == NULL || (Obj->m_StickRegion == NULL && Region->PointInRegion(Obj->m_PosX, Obj->m_PosY)))) {
+ Objects.Add(Obj);
+ }
+ }
+
+ // sort by m_PosY
+ qsort(Objects.GetData(), Objects.GetSize(), sizeof(CAdObject *), CAdScene::CompareObjs);
+
+ // display them
+ for (i = 0; i < Objects.GetSize(); i++) {
+ Obj = Objects[i];
+
+ if (Display3DOnly && !Obj->m_Is3D) continue;
+
+ Game->m_Renderer->Setup2D();
+
+ if (Game->m_EditorMode || !Obj->m_EditorOnly) Obj->Display();
+ Obj->m_Drawn = true;
+ }
+
+
+ // display design only objects
+ if (!Display3DOnly) {
+ if (Game->m_EditorMode && Region == NULL) {
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Active && m_Objects[i]->m_EditorOnly) {
+ m_Objects[i]->Display();
+ m_Objects[i]->m_Drawn = true;
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+int CAdScene::CompareObjs(const void *Obj1, const void *Obj2) {
+ CAdObject *Object1 = *(CAdObject **)Obj1;
+ CAdObject *Object2 = *(CAdObject **)Obj2;
+
+ if (Object1->m_PosY < Object2->m_PosY) return -1;
+ else if (Object1->m_PosY > Object2->m_PosY) return 1;
+ else return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::DisplayRegionContentOld(CAdRegion *Region) {
+ CAdGame *AdGame = (CAdGame *)Game;
+ CAdObject *obj;
+ int i;
+
+ // display all objects in region sorted by m_PosY
+ do {
+ obj = NULL;
+ int minY = INT_MAX;
+
+ // global objects
+ for (i = 0; i < AdGame->m_Objects.GetSize(); i++) {
+ if (AdGame->m_Objects[i]->m_Active && !AdGame->m_Objects[i]->m_Drawn && AdGame->m_Objects[i]->m_PosY < minY && (AdGame->m_Objects[i]->m_StickRegion == Region || Region == NULL || (AdGame->m_Objects[i]->m_StickRegion == NULL && Region->PointInRegion(AdGame->m_Objects[i]->m_PosX, AdGame->m_Objects[i]->m_PosY)))) {
+ obj = AdGame->m_Objects[i];
+ minY = AdGame->m_Objects[i]->m_PosY;
+ }
+ }
+
+ // scene objects
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Active && !m_Objects[i]->m_EditorOnly && !m_Objects[i]->m_Drawn && m_Objects[i]->m_PosY < minY && (m_Objects[i]->m_StickRegion == Region || Region == NULL || (m_Objects[i]->m_StickRegion == NULL && Region->PointInRegion(m_Objects[i]->m_PosX, m_Objects[i]->m_PosY)))) {
+ obj = m_Objects[i];
+ minY = m_Objects[i]->m_PosY;
+ }
+ }
+
+
+ if (obj != NULL) {
+ Game->m_Renderer->Setup2D();
+
+ if (Game->m_EditorMode || !obj->m_EditorOnly) obj->Display();
+ obj->m_Drawn = true;
+ }
+ } while (obj != NULL);
+
+
+ // design only objects
+ if (Game->m_EditorMode && Region == NULL) {
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Active && m_Objects[i]->m_EditorOnly) {
+ m_Objects[i]->Display();
+ m_Objects[i]->m_Drawn = true;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::Update() {
+ return TraverseNodes(true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::ScrollTo(int OffsetX, int OffsetY) {
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ int OrigOffsetLeft = m_TargetOffsetLeft;
+ int OrigOffsetTop = m_TargetOffsetTop;
+
+ m_TargetOffsetLeft = std::max(0, OffsetX - ViewportWidth / 2);
+ m_TargetOffsetLeft = std::min(m_TargetOffsetLeft, m_Width - ViewportWidth);
+
+ m_TargetOffsetTop = std::max(0, OffsetY - ViewportHeight / 2);
+ m_TargetOffsetTop = std::min(m_TargetOffsetTop, m_Height - ViewportHeight);
+
+
+ if (Game->m_MainObject && Game->m_MainObject->m_Is3D) {
+ if (abs(OrigOffsetLeft - m_TargetOffsetLeft) < 5) m_TargetOffsetLeft = OrigOffsetLeft;
+ if (abs(OrigOffsetTop - m_TargetOffsetTop) < 5) m_TargetOffsetTop = OrigOffsetTop;
+ //m_TargetOffsetTop = 0;
+ }
+
+ m_Ready = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::ScrollToObject(CBObject *Object) {
+ if (Object) ScrollTo(Object->m_PosX, Object->m_PosY - Object->GetHeight() / 2);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::SkipToObject(CBObject *Object) {
+ if (Object) SkipTo(Object->m_PosX, Object->m_PosY - Object->GetHeight() / 2);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::SkipTo(int OffsetX, int OffsetY) {
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ m_OffsetLeft = std::max(0, OffsetX - ViewportWidth / 2);
+ m_OffsetLeft = std::min(m_OffsetLeft, m_Width - ViewportWidth);
+
+ m_OffsetTop = std::max(0, OffsetY - ViewportHeight / 2);
+ m_OffsetTop = std::min(m_OffsetTop, m_Height - ViewportHeight);
+
+ m_TargetOffsetLeft = m_OffsetLeft;
+ m_TargetOffsetTop = m_OffsetTop;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // LoadActor
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "LoadActor") == 0) {
+ Stack->CorrectParams(1);
+ CAdActor *act = new CAdActor(Game);
+ if (act && SUCCEEDED(act->LoadFile(Stack->Pop()->GetString()))) {
+ AddObject(act);
+ Stack->PushNative(act, true);
+ } else {
+ delete act;
+ act = NULL;
+ Stack->PushNULL();
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadEntity") == 0) {
+ Stack->CorrectParams(1);
+ CAdEntity *ent = new CAdEntity(Game);
+ if (ent && SUCCEEDED(ent->LoadFile(Stack->Pop()->GetString()))) {
+ AddObject(ent);
+ Stack->PushNative(ent, true);
+ } else {
+ delete ent;
+ ent = NULL;
+ Stack->PushNULL();
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CreateEntity") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdEntity *Ent = new CAdEntity(Game);
+ AddObject(Ent);
+ if (!Val->IsNULL()) Ent->SetName(Val->GetString());
+ Stack->PushNative(Ent, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // UnloadObject / UnloadActor / UnloadEntity / UnloadActor3D / DeleteEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "UnloadObject") == 0 || strcmp(Name, "UnloadActor") == 0 || strcmp(Name, "UnloadEntity") == 0 || strcmp(Name, "UnloadActor3D") == 0 || strcmp(Name, "DeleteEntity") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *val = Stack->Pop();
+ CAdObject *obj = (CAdObject *)val->GetNative();
+ RemoveObject(obj);
+ if (val->GetType() == VAL_VARIABLE_REF) val->SetNULL();
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SkipTo
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SkipTo") == 0) {
+ Stack->CorrectParams(2);
+ CScValue *val1 = Stack->Pop();
+ CScValue *val2 = Stack->Pop();
+ if (val1->IsNative()) {
+ SkipToObject((CBObject *)val1->GetNative());
+ } else {
+ SkipTo(val1->GetInt(), val2->GetInt());
+ }
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollTo / ScrollToAsync
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollTo") == 0 || strcmp(Name, "ScrollToAsync") == 0) {
+ Stack->CorrectParams(2);
+ CScValue *val1 = Stack->Pop();
+ CScValue *val2 = Stack->Pop();
+ if (val1->IsNative()) {
+ ScrollToObject((CBObject *)val1->GetNative());
+ } else {
+ ScrollTo(val1->GetInt(), val2->GetInt());
+ }
+ if (strcmp(Name, "ScrollTo") == 0) Script->WaitForExclusive(this);
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetLayer
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetLayer") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *val = Stack->Pop();
+ if (val->IsInt()) {
+ int layer = val->GetInt();
+ if (layer < 0 || layer >= m_Layers.GetSize()) Stack->PushNULL();
+ else Stack->PushNative(m_Layers[layer], true);
+ } else {
+ char *LayerName = val->GetString();
+ bool LayerFound = false;
+ for (int i = 0; i < m_Layers.GetSize(); i++) {
+ if (scumm_stricmp(LayerName, m_Layers[i]->m_Name) == 0) {
+ Stack->PushNative(m_Layers[i], true);
+ LayerFound = true;
+ break;
+ }
+ }
+ if (!LayerFound) Stack->PushNULL();
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetWaypointGroup
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetWaypointGroup") == 0) {
+ Stack->CorrectParams(1);
+ int group = Stack->Pop()->GetInt();
+ if (group < 0 || group >= m_WaypointGroups.GetSize()) Stack->PushNULL();
+ else Stack->PushNative(m_WaypointGroups[group], true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetNode
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetNode") == 0) {
+ Stack->CorrectParams(1);
+ char *Name = Stack->Pop()->GetString();
+
+ CBObject *node = GetNodeByName(Name);
+ if (node) Stack->PushNative((CBScriptable *)node, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetFreeNode
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetFreeNode") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdObject *Ret = NULL;
+ if (Val->IsInt()) {
+ int Index = Val->GetInt();
+ if (Index >= 0 && Index < m_Objects.GetSize()) Ret = m_Objects[Index];
+ } else {
+ char *Name = Val->GetString();
+ for (int i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i] && m_Objects[i]->m_Name && scumm_stricmp(m_Objects[i]->m_Name, Name) == 0) {
+ Ret = m_Objects[i];
+ break;
+ }
+ }
+ }
+ if (Ret) Stack->PushNative(Ret, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetRegionAt
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetRegionAt") == 0) {
+ Stack->CorrectParams(3);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+ CScValue *Val = Stack->Pop();
+
+ bool IncludeDecors = false;
+ if (!Val->IsNULL()) IncludeDecors = Val->GetBool();
+
+ if (m_MainLayer) {
+ for (int i = m_MainLayer->m_Nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = m_MainLayer->m_Nodes[i];
+ if (Node->m_Type == OBJECT_REGION && Node->m_Region->m_Active && Node->m_Region->PointInRegion(X, Y)) {
+ if (Node->m_Region->m_Decoration && !IncludeDecors) continue;
+
+ Stack->PushNative(Node->m_Region, true);
+ return S_OK;
+ }
+ }
+ }
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsBlockedAt
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsBlockedAt") == 0) {
+ Stack->CorrectParams(2);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+
+ Stack->PushBool(IsBlockedAt(X, Y));
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsWalkableAt
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsWalkableAt") == 0) {
+ Stack->CorrectParams(2);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+
+ Stack->PushBool(IsWalkableAt(X, Y));
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetScaleAt
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetScaleAt") == 0) {
+ Stack->CorrectParams(2);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+
+ Stack->PushFloat(GetZoomAt(X, Y));
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetRotationAt
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetRotationAt") == 0) {
+ Stack->CorrectParams(2);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+
+ Stack->PushFloat(GetRotationAt(X, Y));
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsScrolling
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsScrolling") == 0) {
+ Stack->CorrectParams(0);
+ bool Ret = false;
+ if (m_AutoScroll) {
+ if (m_TargetOffsetLeft != m_OffsetLeft || m_TargetOffsetTop != m_OffsetTop) Ret = true;
+ }
+
+ Stack->PushBool(Ret);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FadeOut / FadeOutAsync
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "FadeOut") == 0 || strcmp(Name, "FadeOutAsync") == 0) {
+ Stack->CorrectParams(5);
+ uint32 Duration = Stack->Pop()->GetInt(500);
+ byte Red = Stack->Pop()->GetInt(0);
+ byte Green = Stack->Pop()->GetInt(0);
+ byte Blue = Stack->Pop()->GetInt(0);
+ byte Alpha = Stack->Pop()->GetInt(0xFF);
+
+ m_Fader->FadeOut(DRGBA(Red, Green, Blue, Alpha), Duration);
+ if (strcmp(Name, "FadeOutAsync") != 0) Script->WaitFor(m_Fader);
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FadeIn / FadeInAsync
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "FadeIn") == 0 || strcmp(Name, "FadeInAsync") == 0) {
+ Stack->CorrectParams(5);
+ uint32 Duration = Stack->Pop()->GetInt(500);
+ byte Red = Stack->Pop()->GetInt(0);
+ byte Green = Stack->Pop()->GetInt(0);
+ byte Blue = Stack->Pop()->GetInt(0);
+ byte Alpha = Stack->Pop()->GetInt(0xFF);
+
+ m_Fader->FadeIn(DRGBA(Red, Green, Blue, Alpha), Duration);
+ if (strcmp(Name, "FadeInAsync") != 0) Script->WaitFor(m_Fader);
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetFadeColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetFadeColor") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushInt(m_Fader->GetCurrentColor());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IsPointInViewport
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IsPointInViewport") == 0) {
+ Stack->CorrectParams(2);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+ Stack->PushBool(PointInViewport(X, Y));
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetViewport
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SetViewport") == 0) {
+ Stack->CorrectParams(4);
+ int X = Stack->Pop()->GetInt();
+ int Y = Stack->Pop()->GetInt();
+ int Width = Stack->Pop()->GetInt();
+ int Height = Stack->Pop()->GetInt();
+
+ if (Width <= 0) Width = Game->m_Renderer->m_Width;
+ if (Height <= 0) Height = Game->m_Renderer->m_Height;
+
+ if (!m_Viewport) m_Viewport = new CBViewport(Game);
+ if (m_Viewport) m_Viewport->SetRect(X, Y, X + Width, Y + Height);
+
+ Stack->PushBool(true);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddLayer
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddLayer") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdLayer *Layer = new CAdLayer(Game);
+ if (!Val->IsNULL()) Layer->SetName(Val->GetString());
+ if (m_MainLayer) {
+ Layer->m_Width = m_MainLayer->m_Width;
+ Layer->m_Height = m_MainLayer->m_Height;
+ }
+ m_Layers.Add(Layer);
+ Game->RegisterObject(Layer);
+
+ Stack->PushNative(Layer, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InsertLayer
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InsertLayer") == 0) {
+ Stack->CorrectParams(2);
+ int Index = Stack->Pop()->GetInt();
+ CScValue *Val = Stack->Pop();
+
+ CAdLayer *Layer = new CAdLayer(Game);
+ if (!Val->IsNULL()) Layer->SetName(Val->GetString());
+ if (m_MainLayer) {
+ Layer->m_Width = m_MainLayer->m_Width;
+ Layer->m_Height = m_MainLayer->m_Height;
+ }
+ if (Index < 0) Index = 0;
+ if (Index <= m_Layers.GetSize() - 1) m_Layers.InsertAt(Index, Layer);
+ else m_Layers.Add(Layer);
+
+ Game->RegisterObject(Layer);
+
+ Stack->PushNative(Layer, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteLayer
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DeleteLayer") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *Val = Stack->Pop();
+
+ CAdLayer *ToDelete = NULL;
+ if (Val->IsNative()) {
+ CBScriptable *Temp = Val->GetNative();
+ for (int i = 0; i < m_Layers.GetSize(); i++) {
+ if (m_Layers[i] == Temp) {
+ ToDelete = m_Layers[i];
+ break;
+ }
+ }
+ } else {
+ int Index = Val->GetInt();
+ if (Index >= 0 && Index < m_Layers.GetSize()) {
+ ToDelete = m_Layers[Index];
+ }
+ }
+ if (ToDelete == NULL) {
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ if (ToDelete->m_Main) {
+ Script->RuntimeError("Scene.DeleteLayer - cannot delete main scene layer");
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ for (int i = 0; i < m_Layers.GetSize(); i++) {
+ if (m_Layers[i] == ToDelete) {
+ m_Layers.RemoveAt(i);
+ Game->UnregisterObject(ToDelete);
+ break;
+ }
+ }
+ Stack->PushBool(true);
+ return S_OK;
+ }
+
+ else return CBObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdScene::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("scene");
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumLayers (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumLayers") == 0) {
+ m_ScValue->SetInt(m_Layers.GetSize());
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumWaypointGroups (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumWaypointGroups") == 0) {
+ m_ScValue->SetInt(m_WaypointGroups.GetSize());
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MainLayer (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MainLayer") == 0) {
+ if (m_MainLayer) m_ScValue->SetNative(m_MainLayer, true);
+ else m_ScValue->SetNULL();
+
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumFreeNodes (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumFreeNodes") == 0) {
+ m_ScValue->SetInt(m_Objects.GetSize());
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MouseX (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MouseX") == 0) {
+ int ViewportX;
+ GetViewportOffset(&ViewportX);
+
+ m_ScValue->SetInt(Game->m_MousePos.x + m_OffsetLeft - ViewportX);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MouseY (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MouseY") == 0) {
+ int ViewportY;
+ GetViewportOffset(NULL, &ViewportY);
+
+ m_ScValue->SetInt(Game->m_MousePos.y + m_OffsetTop - ViewportY);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AutoScroll
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AutoScroll") == 0) {
+ m_ScValue->SetBool(m_AutoScroll);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentState
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentState") == 0) {
+ m_ScValue->SetBool(m_PersistentState);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentStateSprites
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentStateSprites") == 0) {
+ m_ScValue->SetBool(m_PersistentStateSprites);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsX") == 0) {
+ m_ScValue->SetInt(m_ScrollPixelsH);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsY") == 0) {
+ m_ScValue->SetInt(m_ScrollPixelsV);
+ return m_ScValue;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedX") == 0) {
+ m_ScValue->SetInt(m_ScrollTimeH);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedY") == 0) {
+ m_ScValue->SetInt(m_ScrollTimeV);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetX") == 0) {
+ m_ScValue->SetInt(m_OffsetLeft);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetY") == 0) {
+ m_ScValue->SetInt(m_OffsetTop);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Width (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ if (m_MainLayer) m_ScValue->SetInt(m_MainLayer->m_Width);
+ else m_ScValue->SetInt(0);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Height (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ if (m_MainLayer) m_ScValue->SetInt(m_MainLayer->m_Height);
+ else m_ScValue->SetInt(0);
+ return m_ScValue;
+ }
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::ScSetProperty(char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AutoScroll
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AutoScroll") == 0) {
+ m_AutoScroll = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentState
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentState") == 0) {
+ m_PersistentState = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentStateSprites
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentStateSprites") == 0) {
+ m_PersistentStateSprites = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsX") == 0) {
+ m_ScrollPixelsH = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsY") == 0) {
+ m_ScrollPixelsV = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedX") == 0) {
+ m_ScrollTimeH = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedY") == 0) {
+ m_ScrollTimeV = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetX") == 0) {
+ m_OffsetLeft = Value->GetInt();
+
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ m_OffsetLeft = std::max(0, m_OffsetLeft - ViewportWidth / 2);
+ m_OffsetLeft = std::min(m_OffsetLeft, m_Width - ViewportWidth);
+ m_TargetOffsetLeft = m_OffsetLeft;
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetY") == 0) {
+ m_OffsetTop = Value->GetInt();
+
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ m_OffsetTop = std::max(0, m_OffsetTop - ViewportHeight / 2);
+ m_OffsetTop = std::min(m_OffsetTop, m_Height - ViewportHeight);
+ m_TargetOffsetTop = m_OffsetTop;
+
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdScene::ScToString() {
+ return "[scene object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::AddObject(CAdObject *Object) {
+ m_Objects.Add(Object);
+ return Game->RegisterObject(Object);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::RemoveObject(CAdObject *Object) {
+ for (int i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i] == Object) {
+ m_Objects.RemoveAt(i);
+ return Game->UnregisterObject(Object);
+ }
+ }
+ return E_FAIL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ int i;
+
+ Buffer->PutTextIndent(Indent, "SCENE {\n");
+
+ Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", m_Name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+
+ if (m_PersistentState)
+ Buffer->PutTextIndent(Indent + 2, "PERSISTENT_STATE=%s\n", m_PersistentState ? "TRUE" : "FALSE");
+
+ if (!m_PersistentStateSprites)
+ Buffer->PutTextIndent(Indent + 2, "PERSISTENT_STATE_SPRITES=%s\n", m_PersistentStateSprites ? "TRUE" : "FALSE");
+
+
+ // scripts
+ for (i = 0; i < m_Scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_Filename);
+ }
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // properties
+ if (m_ScProp) m_ScProp->SaveAsText(Buffer, Indent + 2);
+
+ // viewport
+ if (m_Viewport) {
+ RECT *rc = m_Viewport->GetRect();
+ Buffer->PutTextIndent(Indent + 2, "VIEWPORT { %d, %d, %d, %d }\n", rc->left, rc->top, rc->right, rc->bottom);
+ }
+
+
+
+ // editor settings
+ Buffer->PutTextIndent(Indent + 2, "; ----- editor settings\n");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_MARGIN_H=%d\n", m_EditorMarginH);
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_MARGIN_V=%d\n", m_EditorMarginV);
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_FRAME { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColFrame), D3DCOLGetG(m_EditorColFrame), D3DCOLGetB(m_EditorColFrame), D3DCOLGetA(m_EditorColFrame));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_ENTITY_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColEntitySel), D3DCOLGetG(m_EditorColEntitySel), D3DCOLGetB(m_EditorColEntitySel), D3DCOLGetA(m_EditorColEntitySel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_REGION_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColRegionSel), D3DCOLGetG(m_EditorColRegionSel), D3DCOLGetB(m_EditorColRegionSel), D3DCOLGetA(m_EditorColRegionSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_BLOCKED_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColBlockedSel), D3DCOLGetG(m_EditorColBlockedSel), D3DCOLGetB(m_EditorColBlockedSel), D3DCOLGetA(m_EditorColBlockedSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_DECORATION_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColDecorSel), D3DCOLGetG(m_EditorColDecorSel), D3DCOLGetB(m_EditorColDecorSel), D3DCOLGetA(m_EditorColDecorSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_WAYPOINTS_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColWaypointsSel), D3DCOLGetG(m_EditorColWaypointsSel), D3DCOLGetB(m_EditorColWaypointsSel), D3DCOLGetA(m_EditorColWaypointsSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_ENTITY { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColEntity), D3DCOLGetG(m_EditorColEntity), D3DCOLGetB(m_EditorColEntity), D3DCOLGetA(m_EditorColEntity));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_REGION { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColRegion), D3DCOLGetG(m_EditorColRegion), D3DCOLGetB(m_EditorColRegion), D3DCOLGetA(m_EditorColRegion));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_DECORATION { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColDecor), D3DCOLGetG(m_EditorColDecor), D3DCOLGetB(m_EditorColDecor), D3DCOLGetA(m_EditorColDecor));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_BLOCKED { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColBlocked), D3DCOLGetG(m_EditorColBlocked), D3DCOLGetB(m_EditorColBlocked), D3DCOLGetA(m_EditorColBlocked));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_WAYPOINTS { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColWaypoints), D3DCOLGetG(m_EditorColWaypoints), D3DCOLGetB(m_EditorColWaypoints), D3DCOLGetA(m_EditorColWaypoints));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_SCALE { %d,%d,%d,%d }\n", D3DCOLGetR(m_EditorColScale), D3DCOLGetG(m_EditorColScale), D3DCOLGetB(m_EditorColScale), D3DCOLGetA(m_EditorColScale));
+
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_REGIONS=%s\n", m_EditorShowRegions ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_BLOCKED=%s\n", m_EditorShowBlocked ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_DECORATION=%s\n", m_EditorShowDecor ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_ENTITIES=%s\n", m_EditorShowEntities ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_SCALE=%s\n", m_EditorShowScale ? "TRUE" : "FALSE");
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ // waypoints
+ Buffer->PutTextIndent(Indent + 2, "; ----- waypoints\n");
+ for (i = 0; i < m_WaypointGroups.GetSize(); i++) m_WaypointGroups[i]->SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // layers
+ Buffer->PutTextIndent(Indent + 2, "; ----- layers\n");
+ for (i = 0; i < m_Layers.GetSize(); i++) m_Layers[i]->SaveAsText(Buffer, Indent + 2);
+
+ // scale levels
+ Buffer->PutTextIndent(Indent + 2, "; ----- scale levels\n");
+ for (i = 0; i < m_ScaleLevels.GetSize(); i++) m_ScaleLevels[i]->SaveAsText(Buffer, Indent + 2);
+
+ // rotation levels
+ Buffer->PutTextIndent(Indent + 2, "; ----- rotation levels\n");
+ for (i = 0; i < m_RotLevels.GetSize(); i++) m_RotLevels[i]->SaveAsText(Buffer, Indent + 2);
+
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // free entities
+ Buffer->PutTextIndent(Indent + 2, "; ----- free entities\n");
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Type == OBJECT_ENTITY) {
+ m_Objects[i]->SaveAsText(Buffer, Indent + 2);
+
+ }
+ }
+
+
+
+ Buffer->PutTextIndent(Indent, "}\n");
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::SortScaleLevels() {
+ bool changed;
+ do {
+ changed = false;
+ for (int i = 0; i < m_ScaleLevels.GetSize() - 1; i++) {
+ if (m_ScaleLevels[i]->m_PosY > m_ScaleLevels[i + 1]->m_PosY) {
+ CAdScaleLevel *sl = m_ScaleLevels[i];
+ m_ScaleLevels[i] = m_ScaleLevels[i + 1];
+ m_ScaleLevels[i + 1] = sl;
+
+ changed = true;
+ }
+ }
+
+ } while (changed);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::SortRotLevels() {
+ bool changed;
+ do {
+ changed = false;
+ for (int i = 0; i < m_RotLevels.GetSize() - 1; i++) {
+ if (m_RotLevels[i]->m_PosX > m_RotLevels[i + 1]->m_PosX) {
+ CAdRotLevel *rl = m_RotLevels[i];
+ m_RotLevels[i] = m_RotLevels[i + 1];
+ m_RotLevels[i + 1] = rl;
+
+ changed = true;
+ }
+ }
+
+ } while (changed);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+float CAdScene::GetScaleAt(int Y) {
+ CAdScaleLevel *prev = NULL;
+ CAdScaleLevel *next = NULL;
+
+ for (int i = 0; i < m_ScaleLevels.GetSize(); i++) {
+ CAdScaleLevel *xxx = m_ScaleLevels[i];
+ int j = m_ScaleLevels.GetSize();
+ if (m_ScaleLevels[i]->m_PosY < Y) prev = m_ScaleLevels[i];
+ else {
+ next = m_ScaleLevels[i];
+ break;
+ }
+ }
+
+ if (prev == NULL || next == NULL) return 100;
+
+ int delta_y = next->m_PosY - prev->m_PosY;
+ float delta_scale = next->m_Scale - prev->m_Scale;
+ Y -= prev->m_PosY;
+
+ float percent = (float)Y / ((float)delta_y / 100.0f);
+ return prev->m_Scale + delta_scale / 100 * percent;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_AutoScroll));
+ PersistMgr->Transfer(TMEMBER(m_EditorColBlocked));
+ PersistMgr->Transfer(TMEMBER(m_EditorColBlockedSel));
+ PersistMgr->Transfer(TMEMBER(m_EditorColDecor));
+ PersistMgr->Transfer(TMEMBER(m_EditorColDecorSel));
+ PersistMgr->Transfer(TMEMBER(m_EditorColEntity));
+ PersistMgr->Transfer(TMEMBER(m_EditorColEntitySel));
+ PersistMgr->Transfer(TMEMBER(m_EditorColFrame));
+ PersistMgr->Transfer(TMEMBER(m_EditorColRegion));
+ PersistMgr->Transfer(TMEMBER(m_EditorColRegionSel));
+ PersistMgr->Transfer(TMEMBER(m_EditorColScale));
+ PersistMgr->Transfer(TMEMBER(m_EditorColWaypoints));
+ PersistMgr->Transfer(TMEMBER(m_EditorColWaypointsSel));
+ PersistMgr->Transfer(TMEMBER(m_EditorMarginH));
+ PersistMgr->Transfer(TMEMBER(m_EditorMarginV));
+ PersistMgr->Transfer(TMEMBER(m_EditorShowBlocked));
+ PersistMgr->Transfer(TMEMBER(m_EditorShowDecor));
+ PersistMgr->Transfer(TMEMBER(m_EditorShowEntities));
+ PersistMgr->Transfer(TMEMBER(m_EditorShowRegions));
+ PersistMgr->Transfer(TMEMBER(m_EditorShowScale));
+ PersistMgr->Transfer(TMEMBER(m_Fader));
+ PersistMgr->Transfer(TMEMBER(m_Height));
+ PersistMgr->Transfer(TMEMBER(m_Initialized));
+ PersistMgr->Transfer(TMEMBER(m_LastTimeH));
+ PersistMgr->Transfer(TMEMBER(m_LastTimeV));
+ m_Layers.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_MainLayer));
+ m_Objects.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_OffsetLeft));
+ PersistMgr->Transfer(TMEMBER(m_OffsetTop));
+ PersistMgr->Transfer(TMEMBER(m_ParalaxScrolling));
+ PersistMgr->Transfer(TMEMBER(m_PersistentState));
+ PersistMgr->Transfer(TMEMBER(m_PersistentStateSprites));
+ PersistMgr->Transfer(TMEMBER(m_PFMaxTime));
+ m_PFPath.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_PFPointsNum));
+ PersistMgr->Transfer(TMEMBER(m_PFReady));
+ PersistMgr->Transfer(TMEMBER(m_PFRequester));
+ PersistMgr->Transfer(TMEMBER(m_PFTarget));
+ PersistMgr->Transfer(TMEMBER(m_PFTargetPath));
+ m_RotLevels.Persist(PersistMgr);
+ m_ScaleLevels.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_ScrollPixelsH));
+ PersistMgr->Transfer(TMEMBER(m_ScrollPixelsV));
+ PersistMgr->Transfer(TMEMBER(m_ScrollTimeH));
+ PersistMgr->Transfer(TMEMBER(m_ScrollTimeV));
+ PersistMgr->Transfer(TMEMBER(m_ShieldWindow));
+ PersistMgr->Transfer(TMEMBER(m_TargetOffsetLeft));
+ PersistMgr->Transfer(TMEMBER(m_TargetOffsetTop));
+ m_WaypointGroups.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(m_Viewport));
+ PersistMgr->Transfer(TMEMBER(m_Width));
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::AfterLoad() {
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::CorrectTargetPoint2(int StartX, int StartY, int *TargetX, int *TargetY, bool CheckFreeObjects, CBObject *Requester) {
+ double xStep, yStep, X, Y;
+ int xLength, yLength, xCount, yCount;
+ int X1, Y1, X2, Y2;
+
+ X1 = *TargetX;
+ Y1 = *TargetY;
+ X2 = StartX;
+ Y2 = StartY;
+
+
+ xLength = abs(X2 - X1);
+ yLength = abs(Y2 - Y1);
+
+ if (xLength > yLength) {
+ /*
+ if(X1 > X2)
+ {
+ Swap(&X1, &X2);
+ Swap(&Y1, &Y2);
+ }
+ */
+
+ yStep = fabs((double)(Y2 - Y1) / (double)(X2 - X1));
+ Y = Y1;
+
+ for (xCount = X1; xCount < X2; xCount++) {
+ if (IsWalkableAt(xCount, (int)Y, CheckFreeObjects, Requester)) {
+ *TargetX = xCount;
+ *TargetY = (int)Y;
+ return S_OK;
+ }
+ Y += yStep;
+ }
+ } else {
+ /*
+ if(Y1 > Y2) {
+ Swap(&X1, &X2);
+ Swap(&Y1, &Y2);
+ }
+ */
+
+ xStep = fabs((double)(X2 - X1) / (double)(Y2 - Y1));
+ X = X1;
+
+ for (yCount = Y1; yCount < Y2; yCount++) {
+ if (IsWalkableAt((int)X, yCount, CheckFreeObjects, Requester)) {
+ *TargetX = (int)X;
+ *TargetY = yCount;
+ return S_OK;
+ }
+ X += xStep;
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::CorrectTargetPoint(int StartX, int StartY, int *X, int *Y, bool CheckFreeObjects, CBObject *Requester) {
+ int x = *X;
+ int y = *Y;
+
+ if (IsWalkableAt(x, y, CheckFreeObjects, Requester) || !m_MainLayer) {
+ return S_OK;
+ }
+
+ // right
+ int length_right = 0;
+ bool found_right = false;
+ for (x = *X, y = *Y; x < m_MainLayer->m_Width; x++, length_right++) {
+ if (IsWalkableAt(x, y, CheckFreeObjects, Requester) && IsWalkableAt(x - 5, y, CheckFreeObjects, Requester)) {
+ found_right = true;
+ break;
+ }
+ }
+
+ // left
+ int length_left = 0;
+ bool found_left = false;
+ for (x = *X, y = *Y; x >= 0; x--, length_left--) {
+ if (IsWalkableAt(x, y, CheckFreeObjects, Requester) && IsWalkableAt(x + 5, y, CheckFreeObjects, Requester)) {
+ found_left = true;
+ break;
+ }
+ }
+
+ // up
+ int length_up = 0;
+ bool found_up = false;
+ for (x = *X, y = *Y; y >= 0; y--, length_up--) {
+ if (IsWalkableAt(x, y, CheckFreeObjects, Requester) && IsWalkableAt(x, y + 5, CheckFreeObjects, Requester)) {
+ found_up = true;
+ break;
+ }
+ }
+
+ // down
+ int length_down = 0;
+ bool found_down = false;
+ for (x = *X, y = *Y; y < m_MainLayer->m_Height; y++, length_down++) {
+ if (IsWalkableAt(x, y, CheckFreeObjects, Requester) && IsWalkableAt(x, y - 5, CheckFreeObjects, Requester)) {
+ found_down = true;
+ break;
+ }
+ }
+
+ if (!found_left && !found_right && !found_up && !found_down) {
+ return S_OK;
+ }
+
+ int OffsetX = INT_MAX, OffsetY = INT_MAX;
+
+ if (found_left && found_right) {
+ if (abs(length_left) < abs(length_right)) OffsetX = length_left;
+ else OffsetX = length_right;
+ } else if (found_left) OffsetX = length_left;
+ else if (found_right) OffsetX = length_right;
+
+ if (found_up && found_down) {
+ if (abs(length_up) < abs(length_down)) OffsetY = length_up;
+ else OffsetY = length_down;
+ } else if (found_up) OffsetY = length_up;
+ else if (found_down) OffsetY = length_down;
+
+ if (abs(OffsetX) < abs(OffsetY))
+ *X = *X + OffsetX;
+ else
+ *Y = *Y + OffsetY;
+
+ if (!IsWalkableAt(*X, *Y)) return CorrectTargetPoint2(StartX, StartY, X, Y, CheckFreeObjects, Requester);
+ else return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::PFPointsStart() {
+ m_PFPointsNum = 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::PFPointsAdd(int X, int Y, int Distance) {
+ if (m_PFPointsNum >= m_PFPath.GetSize()) {
+ m_PFPath.Add(new CAdPathPoint(X, Y, Distance));
+ } else {
+ m_PFPath[m_PFPointsNum]->x = X;
+ m_PFPath[m_PFPointsNum]->y = Y;
+ m_PFPath[m_PFPointsNum]->m_Distance = Distance;
+ m_PFPath[m_PFPointsNum]->m_Marked = false;
+ m_PFPath[m_PFPointsNum]->m_Origin = NULL;
+ }
+
+ m_PFPointsNum++;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::GetViewportOffset(int *OffsetX, int *OffsetY) {
+ CAdGame *AdGame = (CAdGame *)Game;
+ if (m_Viewport && !Game->m_EditorMode) {
+ if (OffsetX) *OffsetX = m_Viewport->m_OffsetX;
+ if (OffsetY) *OffsetY = m_Viewport->m_OffsetY;
+ } else if (AdGame->m_SceneViewport && !Game->m_EditorMode) {
+ if (OffsetX) *OffsetX = AdGame->m_SceneViewport->m_OffsetX;
+ if (OffsetY) *OffsetY = AdGame->m_SceneViewport->m_OffsetY;
+ } else {
+ if (OffsetX) *OffsetX = 0;
+ if (OffsetY) *OffsetY = 0;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::GetViewportSize(int *Width, int *Height) {
+ CAdGame *AdGame = (CAdGame *)Game;
+ if (m_Viewport && !Game->m_EditorMode) {
+ if (Width) *Width = m_Viewport->GetWidth();
+ if (Height) *Height = m_Viewport->GetHeight();
+ } else if (AdGame->m_SceneViewport && !Game->m_EditorMode) {
+ if (Width) *Width = AdGame->m_SceneViewport->GetWidth();
+ if (Height) *Height = AdGame->m_SceneViewport->GetHeight();
+ } else {
+ if (Width) *Width = Game->m_Renderer->m_Width;
+ if (Height) *Height = Game->m_Renderer->m_Height;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdScene::GetOffsetLeft() {
+ int ViewportX;
+ GetViewportOffset(&ViewportX);
+
+ return m_OffsetLeft - ViewportX;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdScene::GetOffsetTop() {
+ int ViewportY;
+ GetViewportOffset(NULL, &ViewportY);
+
+ return m_OffsetTop - ViewportY;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdScene::PointInViewport(int X, int Y) {
+ int Left, Top, Width, Height;
+
+ GetViewportOffset(&Left, &Top);
+ GetViewportSize(&Width, &Height);
+
+ return X >= Left && X <= Left + Width && Y >= Top && Y <= Top + Height;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::SetOffset(int OffsetLeft, int OffsetTop) {
+ m_OffsetLeft = OffsetLeft;
+ m_OffsetTop = OffsetTop;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBObject *CAdScene::GetNodeByName(char *Name) {
+ int i;
+ CBObject *ret = NULL;
+
+ // dependent objects
+ for (i = 0; i < m_Layers.GetSize(); i++) {
+ CAdLayer *layer = m_Layers[i];
+ for (int j = 0; j < layer->m_Nodes.GetSize(); j++) {
+ CAdSceneNode *node = layer->m_Nodes[j];
+ if ((node->m_Type == OBJECT_ENTITY && !scumm_stricmp(Name, node->m_Entity->m_Name)) ||
+ (node->m_Type == OBJECT_REGION && !scumm_stricmp(Name, node->m_Region->m_Name))) {
+ switch (node->m_Type) {
+ case OBJECT_ENTITY:
+ ret = node->m_Entity;
+ break;
+ case OBJECT_REGION:
+ ret = node->m_Region;
+ break;
+ default:
+ ret = NULL;
+ }
+ return ret;
+ }
+ }
+ }
+
+ // free entities
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Type == OBJECT_ENTITY && !scumm_stricmp(Name, m_Objects[i]->m_Name)) {
+ return m_Objects[i];
+ }
+ }
+
+ // waypoint groups
+ for (i = 0; i < m_WaypointGroups.GetSize(); i++) {
+ if (!scumm_stricmp(Name, m_WaypointGroups[i]->m_Name)) {
+ return m_WaypointGroups[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::SaveState() {
+ return PersistState(true);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::LoadState() {
+ return PersistState(false);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::PersistState(bool Saving) {
+ if (!m_PersistentState) return S_OK;
+
+ CAdGame *AdGame = (CAdGame *)Game;
+ CAdSceneState *State = AdGame->GetSceneState(m_Filename, Saving);
+ if (!State) return S_OK;
+
+
+ int i;
+ CAdNodeState *NodeState;
+
+ // dependent objects
+ for (i = 0; i < m_Layers.GetSize(); i++) {
+ CAdLayer *layer = m_Layers[i];
+ for (int j = 0; j < layer->m_Nodes.GetSize(); j++) {
+ CAdSceneNode *node = layer->m_Nodes[j];
+ switch (node->m_Type) {
+ case OBJECT_ENTITY:
+ if (!node->m_Entity->m_SaveState) continue;
+ NodeState = State->GetNodeState(node->m_Entity->m_Name, Saving);
+ if (NodeState) {
+ NodeState->TransferEntity(node->m_Entity, m_PersistentStateSprites, Saving);
+ //if(Saving) NodeState->m_Active = node->m_Entity->m_Active;
+ //else node->m_Entity->m_Active = NodeState->m_Active;
+ }
+ break;
+ case OBJECT_REGION:
+ if (!node->m_Region->m_SaveState) continue;
+ NodeState = State->GetNodeState(node->m_Region->m_Name, Saving);
+ if (NodeState) {
+ if (Saving) NodeState->m_Active = node->m_Region->m_Active;
+ else node->m_Region->m_Active = NodeState->m_Active;
+ }
+ break;
+ }
+ }
+ }
+
+ // free entities
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (!m_Objects[i]->m_SaveState) continue;
+ if (m_Objects[i]->m_Type == OBJECT_ENTITY) {
+ NodeState = State->GetNodeState(m_Objects[i]->m_Name, Saving);
+ if (NodeState) {
+ NodeState->TransferEntity((CAdEntity *)m_Objects[i], m_PersistentStateSprites, Saving);
+ //if(Saving) NodeState->m_Active = m_Objects[i]->m_Active;
+ //else m_Objects[i]->m_Active = NodeState->m_Active;
+ }
+ }
+ }
+
+ // waypoint groups
+ for (i = 0; i < m_WaypointGroups.GetSize(); i++) {
+ NodeState = State->GetNodeState(m_WaypointGroups[i]->m_Name, Saving);
+ if (NodeState) {
+ if (Saving) NodeState->m_Active = m_WaypointGroups[i]->m_Active;
+ else m_WaypointGroups[i]->m_Active = NodeState->m_Active;
+ }
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+float CAdScene::GetRotationAt(int X, int Y) {
+ CAdRotLevel *prev = NULL;
+ CAdRotLevel *next = NULL;
+
+ for (int i = 0; i < m_RotLevels.GetSize(); i++) {
+ CAdRotLevel *xxx = m_RotLevels[i];
+ int j = m_RotLevels.GetSize();
+ if (m_RotLevels[i]->m_PosX < X) prev = m_RotLevels[i];
+ else {
+ next = m_RotLevels[i];
+ break;
+ }
+ }
+
+ if (prev == NULL || next == NULL) return 0;
+
+ int delta_x = next->m_PosX - prev->m_PosX;
+ float delta_rot = next->m_Rotation - prev->m_Rotation;
+ X -= prev->m_PosX;
+
+ float percent = (float)X / ((float)delta_x / 100.0f);
+ return prev->m_Rotation + delta_rot / 100 * percent;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::HandleItemAssociations(char *ItemName, bool Show) {
+ int i;
+
+ for (i = 0; i < m_Layers.GetSize(); i++) {
+ CAdLayer *Layer = m_Layers[i];
+ for (int j = 0; j < Layer->m_Nodes.GetSize(); j++) {
+ if (Layer->m_Nodes[j]->m_Type == OBJECT_ENTITY) {
+ CAdEntity *Ent = Layer->m_Nodes[j]->m_Entity;
+
+ if (Ent->m_Item && strcmp(Ent->m_Item, ItemName) == 0) Ent->m_Active = Show;
+ }
+ }
+ }
+
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ if (m_Objects[i]->m_Type == OBJECT_ENTITY) {
+ CAdEntity *Ent = (CAdEntity *)m_Objects[i];
+ if (Ent->m_Item && strcmp(Ent->m_Item, ItemName) == 0) Ent->m_Active = Show;
+ }
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::GetRegionsAt(int X, int Y, CAdRegion **RegionList, int NumRegions) {
+ int i;
+ int NumUsed = 0;
+ if (m_MainLayer) {
+ for (i = m_MainLayer->m_Nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = m_MainLayer->m_Nodes[i];
+ if (Node->m_Type == OBJECT_REGION && Node->m_Region->m_Active && Node->m_Region->PointInRegion(X, Y)) {
+ if (NumUsed < NumRegions - 1) {
+ RegionList[NumUsed] = Node->m_Region;
+ NumUsed++;
+ } else break;
+ }
+ }
+ }
+ for (i = NumUsed; i < NumRegions; i++) {
+ RegionList[i] = NULL;
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::RestoreDeviceObjects() {
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBObject *CAdScene::GetNextAccessObject(CBObject *CurrObject) {
+ CBArray<CAdObject *, CAdObject *> Objects;
+ GetSceneObjects(Objects, true);
+
+ if (Objects.GetSize() == 0) return NULL;
+ else {
+ if (CurrObject != NULL) {
+ for (int i = 0; i < Objects.GetSize(); i++) {
+ if (Objects[i] == CurrObject) {
+ if (i < Objects.GetSize() - 1) return Objects[i + 1];
+ else break;
+ }
+ }
+ }
+ return Objects[0];
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CBObject *CAdScene::GetPrevAccessObject(CBObject *CurrObject) {
+ CBArray<CAdObject *, CAdObject *> Objects;
+ GetSceneObjects(Objects, true);
+
+ if (Objects.GetSize() == 0) return NULL;
+ else {
+ if (CurrObject != NULL) {
+ for (int i = Objects.GetSize() - 1; i >= 0; i--) {
+ if (Objects[i] == CurrObject) {
+ if (i > 0) return Objects[i - 1];
+ else break;
+ }
+ }
+ }
+ return Objects[Objects.GetSize() - 1];
+ }
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::GetSceneObjects(CBArray<CAdObject *, CAdObject *>& Objects, bool InteractiveOnly) {
+ for (int i = 0; i < m_Layers.GetSize(); i++) {
+ // close-up layer -> remove everything below it
+ if (InteractiveOnly && m_Layers[i]->m_CloseUp) Objects.RemoveAll();
+
+
+ for (int j = 0; j < m_Layers[i]->m_Nodes.GetSize(); j++) {
+ CAdSceneNode *Node = m_Layers[i]->m_Nodes[j];
+ switch (Node->m_Type) {
+ case OBJECT_ENTITY: {
+ CAdEntity *Ent = Node->m_Entity;
+ if (Ent->m_Active && (Ent->m_Registrable || !InteractiveOnly))
+ Objects.Add(Ent);
+ }
+ break;
+
+ case OBJECT_REGION: {
+ CBArray<CAdObject *, CAdObject *> RegionObj;
+ GetRegionObjects(Node->m_Region, RegionObj, InteractiveOnly);
+ for (int New = 0; New < RegionObj.GetSize(); New++) {
+ bool Found = false;
+ for (int Old = 0; Old < Objects.GetSize(); Old++) {
+ if (Objects[Old] == RegionObj[New]) {
+ Found = true;
+ break;
+ }
+ }
+ if (!Found) Objects.Add(RegionObj[New]);
+ }
+ //if(RegionObj.GetSize() > 0) Objects.Append(RegionObj);
+ }
+ break;
+ }
+ }
+ }
+
+ // objects outside any region
+ CBArray<CAdObject *, CAdObject *> RegionObj;
+ GetRegionObjects(NULL, RegionObj, InteractiveOnly);
+ for (int New = 0; New < RegionObj.GetSize(); New++) {
+ bool Found = false;
+ for (int Old = 0; Old < Objects.GetSize(); Old++) {
+ if (Objects[Old] == RegionObj[New]) {
+ Found = true;
+ break;
+ }
+ }
+ if (!Found) Objects.Add(RegionObj[New]);
+ }
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::GetRegionObjects(CAdRegion *Region, CBArray<CAdObject *, CAdObject *>& Objects, bool InteractiveOnly) {
+ CAdGame *AdGame = (CAdGame *)Game;
+ CAdObject *Obj;
+
+ int i;
+
+ // global objects
+ for (i = 0; i < AdGame->m_Objects.GetSize(); i++) {
+ Obj = AdGame->m_Objects[i];
+ if (Obj->m_Active && (Obj->m_StickRegion == Region || Region == NULL || (Obj->m_StickRegion == NULL && Region->PointInRegion(Obj->m_PosX, Obj->m_PosY)))) {
+ if (InteractiveOnly && !Obj->m_Registrable) continue;
+
+ Objects.Add(Obj);
+ }
+ }
+
+ // scene objects
+ for (i = 0; i < m_Objects.GetSize(); i++) {
+ Obj = m_Objects[i];
+ if (Obj->m_Active && !Obj->m_EditorOnly && (Obj->m_StickRegion == Region || Region == NULL || (Obj->m_StickRegion == NULL && Region->PointInRegion(Obj->m_PosX, Obj->m_PosY)))) {
+ if (InteractiveOnly && !Obj->m_Registrable) continue;
+
+ Objects.Add(Obj);
+ }
+ }
+
+ // sort by m_PosY
+ qsort(Objects.GetData(), Objects.GetSize(), sizeof(CAdObject *), CAdScene::CompareObjs);
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdScene.h b/engines/wintermute/AdScene.h
new file mode 100644
index 0000000000..c3124cf814
--- /dev/null
+++ b/engines/wintermute/AdScene.h
@@ -0,0 +1,181 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdScene_H__
+#define __WmeAdScene_H__
+
+#include "BFader.h"
+
+namespace WinterMute {
+
+class CUIWindow;
+class CAdObject;
+class CAdRegion;
+class CBViewport;
+class CAdLayer;
+class CBPoint;
+class CAdWaypointGroup;
+class CAdPath;
+class CAdScaleLevel;
+class CAdRotLevel;
+class CAdPathPoint;
+class CAdScene : public CBObject {
+public:
+
+ CBObject *GetNextAccessObject(CBObject *CurrObject);
+ CBObject *GetPrevAccessObject(CBObject *CurrObject);
+ HRESULT GetSceneObjects(CBArray<CAdObject *, CAdObject *>& Objects, bool InteractiveOnly);
+ HRESULT GetRegionObjects(CAdRegion *Region, CBArray<CAdObject *, CAdObject *>& Objects, bool InteractiveOnly);
+
+ HRESULT AfterLoad();
+
+ HRESULT GetRegionsAt(int X, int Y, CAdRegion **RegionList, int NumRegions);
+ HRESULT HandleItemAssociations(char *ItemName, bool Show);
+ CUIWindow *m_ShieldWindow;
+ float GetRotationAt(int X, int Y);
+ HRESULT LoadState();
+ HRESULT SaveState();
+ bool m_PersistentState;
+ bool m_PersistentStateSprites;
+ CBObject *GetNodeByName(char *Name);
+ void SetOffset(int OffsetLeft, int OffsetTop);
+ bool PointInViewport(int X, int Y);
+ int GetOffsetTop();
+ int GetOffsetLeft();
+ HRESULT GetViewportSize(int *Width = NULL, int *Height = NULL);
+ HRESULT GetViewportOffset(int *OffsetX = NULL, int *OffsetY = NULL);
+ CBViewport *m_Viewport;
+ CBFader *m_Fader;
+ int m_PFPointsNum;
+ void PFPointsAdd(int X, int Y, int Distance);
+ void PFPointsStart();
+ bool m_Initialized;
+ HRESULT CorrectTargetPoint(int StartX, int StartY, int *X, int *Y, bool CheckFreeObjects = false, CBObject *Requester = NULL);
+ HRESULT CorrectTargetPoint2(int StartX, int StartY, int *TargetX, int *TargetY, bool CheckFreeObjects, CBObject *Requester);
+ DECLARE_PERSISTENT(CAdScene, CBObject)
+ HRESULT DisplayRegionContent(CAdRegion *Region = NULL, bool Display3DOnly = false);
+ HRESULT DisplayRegionContentOld(CAdRegion *Region = NULL);
+ static int CompareObjs(const void *Obj1, const void *Obj2);
+
+ HRESULT UpdateFreeObjects();
+ HRESULT TraverseNodes(bool Update = false);
+ float GetScaleAt(int Y);
+ HRESULT SortScaleLevels();
+ HRESULT SortRotLevels();
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ uint32 GetAlphaAt(int X, int Y, bool ColorCheck = false);
+ bool m_ParalaxScrolling;
+ void SkipTo(int OffsetX, int OffsetY);
+ void SetDefaults();
+ void Cleanup();
+ void SkipToObject(CBObject *Object);
+ void ScrollToObject(CBObject *Object);
+ void ScrollTo(int OffsetX, int OffsetY);
+ virtual HRESULT Update();
+ bool m_AutoScroll;
+ int m_TargetOffsetTop;
+ int m_TargetOffsetLeft;
+
+ int m_ScrollPixelsV;
+ uint32 m_ScrollTimeV;
+ uint32 m_LastTimeV;
+
+ int m_ScrollPixelsH;
+ uint32 m_ScrollTimeH;
+ uint32 m_LastTimeH;
+
+ virtual HRESULT Display();
+ uint32 m_PFMaxTime;
+ HRESULT InitLoop();
+ void PathFinderStep();
+ bool IsBlockedAt(int X, int Y, bool CheckFreeObjects = false, CBObject *Requester = NULL);
+ bool IsWalkableAt(int X, int Y, bool CheckFreeObjects = false, CBObject *Requester = NULL);
+ CAdLayer *m_MainLayer;
+ float GetZoomAt(int X, int Y);
+ bool GetPath(CBPoint source, CBPoint target, CAdPath *path, CBObject *requester = NULL);
+ CAdScene(CBGame *inGame);
+ virtual ~CAdScene();
+ CBArray<CAdLayer *, CAdLayer *> m_Layers;
+ CBArray<CAdObject *, CAdObject *> m_Objects;
+ CBArray<CAdWaypointGroup *, CAdWaypointGroup *> m_WaypointGroups;
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ int m_Width;
+ int m_Height;
+ HRESULT AddObject(CAdObject *Object);
+ HRESULT RemoveObject(CAdObject *Object);
+ int m_EditorMarginH;
+ int m_EditorMarginV;
+ uint32 m_EditorColFrame;
+ uint32 m_EditorColEntity;
+ uint32 m_EditorColRegion;
+ uint32 m_EditorColBlocked;
+ uint32 m_EditorColWaypoints;
+ uint32 m_EditorColEntitySel;
+ uint32 m_EditorColRegionSel;
+ uint32 m_EditorColBlockedSel;
+ uint32 m_EditorColWaypointsSel;
+ uint32 m_EditorColScale;
+ uint32 m_EditorColDecor;
+ uint32 m_EditorColDecorSel;
+
+ bool m_EditorShowRegions;
+ bool m_EditorShowBlocked;
+ bool m_EditorShowDecor;
+ bool m_EditorShowEntities;
+ bool m_EditorShowScale;
+ CBArray<CAdScaleLevel *, CAdScaleLevel *> m_ScaleLevels;
+ CBArray<CAdRotLevel *, CAdRotLevel *> m_RotLevels;
+
+ virtual HRESULT RestoreDeviceObjects();
+ int GetPointsDist(CBPoint p1, CBPoint p2, CBObject *requester = NULL);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(char *Name);
+ virtual HRESULT ScSetProperty(char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name);
+ virtual char *ScToString();
+
+
+private:
+ HRESULT PersistState(bool Saving = true);
+ void PFAddWaypointGroup(CAdWaypointGroup *Wpt, CBObject *Requester = NULL);
+ bool m_PFReady;
+ CBPoint *m_PFTarget;
+ CAdPath *m_PFTargetPath;
+ CBObject *m_PFRequester;
+ CBArray<CAdPathPoint *, CAdPathPoint *> m_PFPath;
+
+ int m_OffsetTop;
+ int m_OffsetLeft;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdSceneNode.cpp b/engines/wintermute/AdSceneNode.cpp
new file mode 100644
index 0000000000..4f20a47324
--- /dev/null
+++ b/engines/wintermute/AdSceneNode.cpp
@@ -0,0 +1,83 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdSceneNode.h"
+#include "BGame.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSceneNode, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneNode::CAdSceneNode(CBGame *inGame): CBObject(inGame) {
+ m_Type = OBJECT_NONE;
+ m_Region = NULL;
+ m_Entity = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneNode::~CAdSceneNode() {
+ Game->UnregisterObject(m_Region);
+ m_Region = NULL;
+
+ Game->UnregisterObject(m_Entity);
+ m_Entity = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneNode::SetEntity(CAdEntity *Entity) {
+ m_Type = OBJECT_ENTITY;
+ m_Entity = Entity;
+ return Game->RegisterObject(Entity);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneNode::SetRegion(CAdRegion *Region) {
+ m_Type = OBJECT_REGION;
+ m_Region = Region;
+ return Game->RegisterObject(Region);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneNode::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Entity));
+ PersistMgr->Transfer(TMEMBER(m_Region));
+ PersistMgr->Transfer(TMEMBER_INT(m_Type));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdSceneNode.h b/engines/wintermute/AdSceneNode.h
new file mode 100644
index 0000000000..94bd6f9aab
--- /dev/null
+++ b/engines/wintermute/AdSceneNode.h
@@ -0,0 +1,54 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdSceneNode_H__
+#define __WmeAdSceneNode_H__
+
+
+#include "AdTypes.h" // Added by ClassView
+#include "AdRegion.h" // Added by ClassView
+#include "AdEntity.h"
+
+namespace WinterMute {
+
+class CAdSceneNode : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdSceneNode, CBObject)
+ HRESULT SetRegion(CAdRegion *Region);
+ HRESULT SetEntity(CAdEntity *Entity);
+ CAdEntity *m_Entity;
+ CAdRegion *m_Region;
+ TObjectType m_Type;
+ CAdSceneNode(CBGame *inGame);
+ virtual ~CAdSceneNode();
+
+};
+
+}
+
+#endif
diff --git a/engines/wintermute/AdSceneState.cpp b/engines/wintermute/AdSceneState.cpp
new file mode 100644
index 0000000000..7ed571a711
--- /dev/null
+++ b/engines/wintermute/AdSceneState.cpp
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "persistent.h"
+#include "AdSceneState.h"
+#include "AdNodeState.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSceneState, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneState::CAdSceneState(CBGame *inGame): CBBase(inGame) {
+ m_Filename = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneState::~CAdSceneState() {
+ SAFE_DELETE_ARRAY(m_Filename);
+
+ for (int i = 0; i < m_NodeStates.GetSize(); i++) delete m_NodeStates[i];
+ m_NodeStates.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneState::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(m_Filename));
+ m_NodeStates.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSceneState::SetFilename(char *Filename) {
+ SAFE_DELETE_ARRAY(m_Filename);
+ m_Filename = new char [strlen(Filename) + 1];
+ if (m_Filename) strcpy(m_Filename, Filename);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdNodeState *CAdSceneState::GetNodeState(char *Name, bool Saving) {
+ for (int i = 0; i < m_NodeStates.GetSize(); i++) {
+ if (scumm_stricmp(m_NodeStates[i]->m_Name, Name) == 0) return m_NodeStates[i];
+ }
+
+ if (Saving) {
+ CAdNodeState *ret = new CAdNodeState(Game);
+ ret->SetName(Name);
+ m_NodeStates.Add(ret);
+
+ return ret;
+ } else return NULL;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdSceneState.h b/engines/wintermute/AdSceneState.h
new file mode 100644
index 0000000000..6abb5c9a7f
--- /dev/null
+++ b/engines/wintermute/AdSceneState.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdSceneState_H__
+#define __WmeAdSceneState_H__
+
+#include "persistent.h"
+#include "BBase.h"
+#include "coll_templ.h"
+
+namespace WinterMute {
+class CAdNodeState;
+class CAdSceneState : public CBBase {
+public:
+ CAdNodeState *GetNodeState(char *Name, bool Saving);
+ void SetFilename(char *Filename);
+ DECLARE_PERSISTENT(CAdSceneState, CBBase)
+ CAdSceneState(CBGame *inGame);
+ virtual ~CAdSceneState();
+ char *m_Filename;
+ CBArray<CAdNodeState *, CAdNodeState *> m_NodeStates;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdSentence.cpp b/engines/wintermute/AdSentence.cpp
new file mode 100644
index 0000000000..f9574302ed
--- /dev/null
+++ b/engines/wintermute/AdSentence.cpp
@@ -0,0 +1,317 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdSentence.h"
+#include "AdTalkDef.h"
+#include "AdTalkNode.h"
+#include "AdGame.h"
+#include "PathUtil.h"
+#include "BGame.h"
+#include "BSound.h"
+#include "AdScene.h"
+#include "BFont.h"
+#include "BSprite.h"
+#include "BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSentence, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSentence::CAdSentence(CBGame *inGame): CBBase(inGame) {
+ m_Text = NULL;
+ m_Stances = NULL;
+ m_TempStance = NULL;
+
+ m_Duration = 0;
+ m_StartTime = 0;
+ m_CurrentStance = 0;
+
+ m_Font = NULL;
+
+ m_Pos.x = m_Pos.y = 0;
+ m_Width = Game->m_Renderer->m_Width;
+
+ m_Align = (TTextAlign)TAL_CENTER;
+
+ m_Sound = NULL;
+ m_SoundStarted = false;
+
+ m_TalkDef = NULL;
+ m_CurrentSprite = NULL;
+ m_CurrentSkelAnim = NULL;
+ m_FixedPos = false;
+ m_Freezable = true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSentence::~CAdSentence() {
+ delete m_Sound;
+ delete[] m_Text;
+ delete[] m_Stances;
+ delete[] m_TempStance;
+ delete m_TalkDef;
+ m_Sound = NULL;
+ m_Text = NULL;
+ m_Stances = NULL;
+ m_TempStance = NULL;
+ m_TalkDef = NULL;
+
+ m_CurrentSprite = NULL; // ref only
+ m_CurrentSkelAnim = NULL;
+ m_Font = NULL; // ref only
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSentence::SetText(char *Text) {
+ if (m_Text) delete [] m_Text;
+ m_Text = new char[strlen(Text) + 1];
+ if (m_Text) strcpy(m_Text, Text);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSentence::SetStances(char *Stances) {
+ if (m_Stances) delete [] m_Stances;
+ if (Stances) {
+ m_Stances = new char[strlen(Stances) + 1];
+ if (m_Stances) strcpy(m_Stances, Stances);
+ } else m_Stances = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdSentence::GetCurrentStance() {
+ return GetStance(m_CurrentStance);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdSentence::GetNextStance() {
+ m_CurrentStance++;
+ return GetStance(m_CurrentStance);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdSentence::GetStance(int Stance) {
+ if (m_Stances == NULL) return NULL;
+
+ if (m_TempStance) delete [] m_TempStance;
+ m_TempStance = NULL;
+
+ char *start;
+ char *curr;
+ int pos;
+
+ if (Stance == 0) start = m_Stances;
+ else {
+ pos = 0;
+ start = NULL;
+ curr = m_Stances;
+ while (pos < Stance) {
+ if (*curr == '\0') break;
+ if (*curr == ',') pos++;
+ curr++;
+ }
+ if (pos == Stance) start = curr;
+ }
+
+ if (start == NULL) return NULL;
+
+ while (*start == ' ' && *start != ',' && *start != '\0') start++;
+
+ curr = start;
+ while (*curr != '\0' && *curr != ',') curr++;
+
+ while (curr > start && *(curr - 1) == ' ') curr--;
+
+ m_TempStance = new char [curr - start + 1];
+ if (m_TempStance) {
+ m_TempStance[curr - start] = '\0';
+ strncpy(m_TempStance, start, curr - start);
+ }
+
+ return m_TempStance;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Display() {
+ if (!m_Font || !m_Text) return E_FAIL;
+
+ if (m_Sound && !m_SoundStarted) {
+ m_Sound->Play();
+ m_SoundStarted = true;
+ }
+
+ if (Game->m_Subtitles) {
+ int x = m_Pos.x;
+ int y = m_Pos.y;
+
+ if (!m_FixedPos) {
+ x = x - ((CAdGame *)Game)->m_Scene->GetOffsetLeft();
+ y = y - ((CAdGame *)Game)->m_Scene->GetOffsetTop();
+ }
+
+
+ x = std::max(x, 0);
+ x = std::min(x, Game->m_Renderer->m_Width - m_Width);
+ y = std::max(y, 0);
+
+ m_Font->DrawText((byte *)m_Text, x, y, m_Width, m_Align);
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSentence::SetSound(CBSound *Sound) {
+ if (!Sound) return;
+ delete m_Sound;
+ m_Sound = Sound;
+ m_SoundStarted = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Finish() {
+ if (m_Sound) m_Sound->Stop();
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Persist(CBPersistMgr *PersistMgr) {
+
+ PersistMgr->Transfer(TMEMBER(Game));
+
+ PersistMgr->Transfer(TMEMBER_INT(m_Align));
+ PersistMgr->Transfer(TMEMBER(m_CurrentStance));
+ PersistMgr->Transfer(TMEMBER(m_CurrentSprite));
+ PersistMgr->Transfer(TMEMBER(m_CurrentSkelAnim));
+ PersistMgr->Transfer(TMEMBER(m_Duration));
+ PersistMgr->Transfer(TMEMBER(m_Font));
+ PersistMgr->Transfer(TMEMBER(m_Pos));
+ PersistMgr->Transfer(TMEMBER(m_Sound));
+ PersistMgr->Transfer(TMEMBER(m_SoundStarted));
+ PersistMgr->Transfer(TMEMBER(m_Stances));
+ PersistMgr->Transfer(TMEMBER(m_StartTime));
+ PersistMgr->Transfer(TMEMBER(m_TalkDef));
+ PersistMgr->Transfer(TMEMBER(m_TempStance));
+ PersistMgr->Transfer(TMEMBER(m_Text));
+ PersistMgr->Transfer(TMEMBER(m_Width));
+ PersistMgr->Transfer(TMEMBER(m_FixedPos));
+ PersistMgr->Transfer(TMEMBER(m_Freezable));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::SetupTalkFile(char *SoundFilename) {
+ delete m_TalkDef;
+ m_TalkDef = NULL;
+ m_CurrentSprite = NULL;
+
+ if (!SoundFilename) return S_OK;
+
+
+ AnsiString path = PathUtil::GetDirectoryName(SoundFilename);
+ AnsiString name = PathUtil::GetFileNameWithoutExtension(SoundFilename);
+
+ AnsiString talkDefFileName = PathUtil::Combine(path, name + ".talk");
+
+ CBFile *file = Game->m_FileManager->OpenFile(talkDefFileName.c_str());
+ if (file) {
+ Game->m_FileManager->CloseFile(file);
+ } else return S_OK; // no talk def file found
+
+
+ m_TalkDef = new CAdTalkDef(Game);
+ if (!m_TalkDef || FAILED(m_TalkDef->LoadFile(talkDefFileName.c_str()))) {
+ delete m_TalkDef;
+ m_TalkDef = NULL;
+ return E_FAIL;
+ }
+ //Game->LOG(0, "Using .talk file: %s", TalkDefFile);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Update(TDirection Dir) {
+ if (!m_TalkDef) return S_OK;
+
+ uint32 CurrentTime;
+ // if sound is available, synchronize with sound, otherwise use timer
+
+ /*
+ if(m_Sound) CurrentTime = m_Sound->GetPositionTime();
+ else CurrentTime = Game->m_Timer - m_StartTime;
+ */
+ CurrentTime = Game->m_Timer - m_StartTime;
+
+ bool TalkNodeFound = false;
+ for (int i = 0; i < m_TalkDef->m_Nodes.GetSize(); i++) {
+ if (m_TalkDef->m_Nodes[i]->IsInTimeInterval(CurrentTime, Dir)) {
+ TalkNodeFound = true;
+
+ CBSprite *NewSprite = m_TalkDef->m_Nodes[i]->GetSprite(Dir);
+ if (NewSprite != m_CurrentSprite) NewSprite->Reset();
+ m_CurrentSprite = NewSprite;
+
+ if (!m_TalkDef->m_Nodes[i]->m_PlayToEnd) break;
+ }
+ }
+
+
+ // no talk node, try to use default sprite instead (if any)
+ if (!TalkNodeFound) {
+ CBSprite *NewSprite = m_TalkDef->GetDefaultSprite(Dir);
+ if (NewSprite) {
+ if (NewSprite != m_CurrentSprite) NewSprite->Reset();
+ m_CurrentSprite = NewSprite;
+ } else m_CurrentSprite = NULL;
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdSentence::CanSkip() {
+ // prevent accidental sentence skipping (TODO make configurable)
+ return (Game->m_Timer - m_StartTime) > 300;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdSentence.h b/engines/wintermute/AdSentence.h
new file mode 100644
index 0000000000..863f5569f1
--- /dev/null
+++ b/engines/wintermute/AdSentence.h
@@ -0,0 +1,83 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdSentence_H__
+#define __WmeAdSentence_H__
+
+
+#include "BBase.h"
+#include "persistent.h"
+#include "dctypes.h" // Added by ClassView
+
+namespace WinterMute {
+class CAdTalkDef;
+class CBFont;
+class CBSprite;
+class CBSound;
+class CAdSentence : public CBBase {
+public:
+ bool m_Freezable;
+ bool m_FixedPos;
+ CBSprite *m_CurrentSprite;
+ char *m_CurrentSkelAnim;
+ HRESULT Update(TDirection Dir = DI_DOWN);
+ HRESULT SetupTalkFile(char *SoundFilename);
+ DECLARE_PERSISTENT(CAdSentence, CBBase)
+ HRESULT Finish();
+ void SetSound(CBSound *Sound);
+ bool m_SoundStarted;
+ CBSound *m_Sound;
+ TTextAlign m_Align;
+ HRESULT Display();
+ int m_Width;
+ POINT m_Pos;
+ CBFont *m_Font;
+ char *GetNextStance();
+ char *GetCurrentStance();
+ void SetStances(char *Stances);
+ void SetText(char *Text);
+ int m_CurrentStance;
+ uint32 m_StartTime;
+ char *m_Stances;
+ char *m_Text;
+ uint32 m_Duration;
+ CAdSentence(CBGame *inGame);
+ virtual ~CAdSentence();
+ CAdTalkDef *m_TalkDef;
+
+ bool CanSkip();
+
+private:
+ char *m_TempStance;
+ char *GetStance(int Stance);
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdSpriteSet.cpp b/engines/wintermute/AdSpriteSet.cpp
new file mode 100644
index 0000000000..f5974c9662
--- /dev/null
+++ b/engines/wintermute/AdSpriteSet.cpp
@@ -0,0 +1,312 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdSpriteSet.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "BGame.h"
+#include "BFileManager.h"
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSpriteSet, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSpriteSet::CAdSpriteSet(CBGame *inGame, CBObject *Owner): CBObject(inGame) {
+ m_Owner = Owner;
+
+ for (int i = 0; i < NUM_DIRECTIONS; i++)
+ m_Sprites[i] = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSpriteSet::~CAdSpriteSet() {
+ for (int i = 0; i < NUM_DIRECTIONS; i++) {
+ delete m_Sprites[i];
+ m_Sprites[i] = NULL;
+ }
+
+ m_Owner = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSpriteSet::LoadFile(char *Filename, int LifeTime, TSpriteCacheType CacheType) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdSpriteSet::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing SPRITESET file '%s'", Filename);
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(SPRITESET)
+TOKEN_DEF(NAME)
+TOKEN_DEF(UP_LEFT)
+TOKEN_DEF(DOWN_LEFT)
+TOKEN_DEF(LEFT)
+TOKEN_DEF(UP_RIGHT)
+TOKEN_DEF(DOWN_RIGHT)
+TOKEN_DEF(RIGHT)
+TOKEN_DEF(UP)
+TOKEN_DEF(DOWN)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSpriteSet::LoadBuffer(byte *Buffer, bool Complete, int LifeTime, TSpriteCacheType CacheType) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(SPRITESET)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(UP_LEFT)
+ TOKEN_TABLE(DOWN_LEFT)
+ TOKEN_TABLE(LEFT)
+ TOKEN_TABLE(UP_RIGHT)
+ TOKEN_TABLE(DOWN_RIGHT)
+ TOKEN_TABLE(RIGHT)
+ TOKEN_TABLE(UP)
+ TOKEN_TABLE(DOWN)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_SPRITESET) {
+ Game->LOG(0, "'SPRITESET' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ CBSprite *spr = NULL;
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_LEFT:
+ delete m_Sprites[DI_LEFT];
+ m_Sprites[DI_LEFT] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_LEFT] = spr;
+ break;
+
+ case TOKEN_RIGHT:
+ delete m_Sprites[DI_RIGHT];
+ m_Sprites[DI_RIGHT] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_RIGHT] = spr;
+ break;
+
+ case TOKEN_UP:
+ delete m_Sprites[DI_UP];
+ m_Sprites[DI_UP] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_UP] = spr;
+ break;
+
+ case TOKEN_DOWN:
+ delete m_Sprites[DI_DOWN];
+ m_Sprites[DI_DOWN] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_DOWN] = spr;
+ break;
+
+ case TOKEN_UP_LEFT:
+ delete m_Sprites[DI_UPLEFT];
+ m_Sprites[DI_UPLEFT] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_UPLEFT] = spr;
+ break;
+
+ case TOKEN_UP_RIGHT:
+ delete m_Sprites[DI_UPRIGHT];
+ m_Sprites[DI_UPRIGHT] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_UPRIGHT] = spr;
+ break;
+
+ case TOKEN_DOWN_LEFT:
+ delete m_Sprites[DI_DOWNLEFT];
+ m_Sprites[DI_DOWNLEFT] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_DOWNLEFT] = spr;
+ break;
+
+ case TOKEN_DOWN_RIGHT:
+ delete m_Sprites[DI_DOWNRIGHT];
+ m_Sprites[DI_DOWNRIGHT] = NULL;
+ spr = new CBSprite(Game, m_Owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else m_Sprites[DI_DOWNRIGHT] = spr;
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in SPRITESET definition");
+ return E_FAIL;
+ }
+
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading SPRITESET definition");
+ if (spr) delete spr;
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSpriteSet::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Owner));
+ for (int i = 0; i < NUM_DIRECTIONS; i++) {
+ PersistMgr->Transfer("", &m_Sprites[i]);
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdSpriteSet::GetSprite(TDirection Direction) {
+ int Dir = (int)Direction;
+ if (Dir < 0) Dir = 0;
+ if (Dir >= NUM_DIRECTIONS) Dir = NUM_DIRECTIONS - 1;
+
+ CBSprite *ret = NULL;
+
+ // find nearest set sprite
+ int i;
+ int NumSteps = 0;
+ for (i = Dir, NumSteps = 0; i >= 0; i--) {
+ if (m_Sprites[i] != NULL) {
+ ret = m_Sprites[i];
+ NumSteps = Dir - i;
+ break;
+ }
+ }
+
+ for (i = Dir; i < NUM_DIRECTIONS; i++) {
+ if (m_Sprites[i] != NULL) {
+ if (ret == NULL || NumSteps > i - Dir) return m_Sprites[i];
+ else return ret;
+ }
+ }
+
+ return ret;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSpriteSet::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "SPRITESET {\n");
+ if (m_Name) Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", m_Name);
+ for (int i = 0; i < NUM_DIRECTIONS; i++) {
+ if (m_Sprites[i]) {
+ switch (i) {
+ case DI_UP:
+ Buffer->PutTextIndent(Indent + 2, "UP=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ case DI_UPRIGHT:
+ Buffer->PutTextIndent(Indent + 2, "UP_RIGHT=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ case DI_RIGHT:
+ Buffer->PutTextIndent(Indent + 2, "RIGHT=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ case DI_DOWNRIGHT:
+ Buffer->PutTextIndent(Indent + 2, "DOWN_RIGHT=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ case DI_DOWN:
+ Buffer->PutTextIndent(Indent + 2, "DOWN=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ case DI_DOWNLEFT:
+ Buffer->PutTextIndent(Indent + 2, "DOWN_LEFT=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ case DI_LEFT:
+ Buffer->PutTextIndent(Indent + 2, "LEFT=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ case DI_UPLEFT:
+ Buffer->PutTextIndent(Indent + 2, "UP_LEFT=\"%s\"\n", m_Sprites[i]->m_Filename);
+ break;
+ }
+ }
+ }
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdSpriteSet::ContainsSprite(CBSprite *Sprite) {
+ if (!Sprite) return NULL;
+
+ for (int i = 0; i < NUM_DIRECTIONS; i++) {
+ if (m_Sprites[i] == Sprite) return true;
+ }
+ return false;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdSpriteSet.h b/engines/wintermute/AdSpriteSet.h
new file mode 100644
index 0000000000..08b1606962
--- /dev/null
+++ b/engines/wintermute/AdSpriteSet.h
@@ -0,0 +1,54 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdSpriteSet_H__
+#define __WmeAdSpriteSet_H__
+
+
+#include "BObject.h"
+#include "BSprite.h" // Added by ClassView
+
+namespace WinterMute {
+
+class CAdSpriteSet : public CBObject {
+public:
+ bool ContainsSprite(CBSprite *Sprite);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent = 0);
+ CBSprite *GetSprite(TDirection Direction);
+ DECLARE_PERSISTENT(CAdSpriteSet, CBObject)
+ CBObject *m_Owner;
+ CAdSpriteSet(CBGame *inGame, CBObject *Owner = NULL);
+ virtual ~CAdSpriteSet();
+ HRESULT LoadFile(char *Filename, int LifeTime = -1, TSpriteCacheType CacheType = CACHE_ALL);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true, int LifeTime = -1, TSpriteCacheType CacheType = CACHE_ALL);
+ CBSprite *m_Sprites[NUM_DIRECTIONS];
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdTalkDef.cpp b/engines/wintermute/AdTalkDef.cpp
new file mode 100644
index 0000000000..77a1c86769
--- /dev/null
+++ b/engines/wintermute/AdTalkDef.cpp
@@ -0,0 +1,260 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdTalkDef.h"
+#include "AdTalkNode.h"
+#include "BParser.h"
+#include "BGame.h"
+#include "BDynBuffer.h"
+#include "BSprite.h"
+#include "AdSpriteSet.h"
+#include "BFileManager.h"
+#include "utils.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdTalkDef, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkDef::CAdTalkDef(CBGame *inGame): CBObject(inGame) {
+ m_DefaultSpriteFilename = NULL;
+ m_DefaultSprite = NULL;
+
+ m_DefaultSpriteSetFilename = NULL;
+ m_DefaultSpriteSet = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkDef::~CAdTalkDef() {
+ for (int i = 0; i < m_Nodes.GetSize(); i++) delete m_Nodes[i];
+ m_Nodes.RemoveAll();
+
+ delete[] m_DefaultSpriteFilename;
+ delete m_DefaultSprite;
+ m_DefaultSpriteFilename = NULL;
+ m_DefaultSprite = NULL;
+
+ delete[] m_DefaultSpriteSetFilename;
+ delete m_DefaultSpriteSet;
+ m_DefaultSpriteSetFilename = NULL;
+ m_DefaultSpriteSet = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::LoadFile(const char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdTalkDef::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ CBUtils::SetString(&m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing TALK file '%s'", Filename);
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(TALK)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(ACTION)
+TOKEN_DEF(DEFAULT_SPRITESET_FILE)
+TOKEN_DEF(DEFAULT_SPRITESET)
+TOKEN_DEF(DEFAULT_SPRITE)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(TALK)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(ACTION)
+ TOKEN_TABLE(DEFAULT_SPRITESET_FILE)
+ TOKEN_TABLE(DEFAULT_SPRITESET)
+ TOKEN_TABLE(DEFAULT_SPRITE)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_TALK) {
+ Game->LOG(0, "'TALK' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_ACTION: {
+ CAdTalkNode *Node = new CAdTalkNode(Game);
+ if (Node && SUCCEEDED(Node->LoadBuffer(params, false))) m_Nodes.Add(Node);
+ else {
+ delete Node;
+ Node = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ }
+ break;
+
+ case TOKEN_DEFAULT_SPRITE:
+ CBUtils::SetString(&m_DefaultSpriteFilename, (char *)params);
+ break;
+
+ case TOKEN_DEFAULT_SPRITESET_FILE:
+ CBUtils::SetString(&m_DefaultSpriteSetFilename, (char *)params);
+ break;
+
+ case TOKEN_DEFAULT_SPRITESET: {
+ delete m_DefaultSpriteSet;
+ m_DefaultSpriteSet = new CAdSpriteSet(Game);
+ if (!m_DefaultSpriteSet || FAILED(m_DefaultSpriteSet->LoadBuffer(params, false))) {
+ delete m_DefaultSpriteSet;
+ m_DefaultSpriteSet = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ }
+ break;
+
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in TALK definition");
+ return E_FAIL;
+ }
+
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading TALK definition");
+ return E_FAIL;
+ }
+
+ delete m_DefaultSprite;
+ delete m_DefaultSpriteSet;
+ m_DefaultSprite = NULL;
+ m_DefaultSpriteSet = NULL;
+
+ if (m_DefaultSpriteFilename) {
+ m_DefaultSprite = new CBSprite(Game);
+ if (!m_DefaultSprite || FAILED(m_DefaultSprite->LoadFile(m_DefaultSpriteFilename))) return E_FAIL;
+ }
+
+ if (m_DefaultSpriteSetFilename) {
+ m_DefaultSpriteSet = new CAdSpriteSet(Game);
+ if (!m_DefaultSpriteSet || FAILED(m_DefaultSpriteSet->LoadFile(m_DefaultSpriteSetFilename))) return E_FAIL;
+ }
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_DefaultSprite));
+ PersistMgr->Transfer(TMEMBER(m_DefaultSpriteFilename));
+ PersistMgr->Transfer(TMEMBER(m_DefaultSpriteSet));
+ PersistMgr->Transfer(TMEMBER(m_DefaultSpriteSetFilename));
+
+ m_Nodes.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "TALK {\n");
+ if (m_DefaultSpriteFilename) Buffer->PutTextIndent(Indent + 2, "DEFAULT_SPRITE=\"%s\"\n", m_DefaultSpriteFilename);
+
+ if (m_DefaultSpriteSetFilename) Buffer->PutTextIndent(Indent + 2, "DEFAULT_SPRITESET_FILE=\"%s\"\n", m_DefaultSpriteSetFilename);
+ else if (m_DefaultSpriteSet) m_DefaultSpriteSet->SaveAsText(Buffer, Indent + 2);
+
+ for (int i = 0; i < m_Nodes.GetSize(); i++) {
+ m_Nodes[i]->SaveAsText(Buffer, Indent + 2);
+ Buffer->PutTextIndent(Indent, "\n");
+ }
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::LoadDefaultSprite() {
+ if (m_DefaultSpriteFilename && !m_DefaultSprite) {
+ m_DefaultSprite = new CBSprite(Game);
+ if (!m_DefaultSprite || FAILED(m_DefaultSprite->LoadFile(m_DefaultSpriteFilename))) {
+ delete m_DefaultSprite;
+ m_DefaultSprite = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ } else if (m_DefaultSpriteSetFilename && !m_DefaultSpriteSet) {
+ m_DefaultSpriteSet = new CAdSpriteSet(Game);
+ if (!m_DefaultSpriteSet || FAILED(m_DefaultSpriteSet->LoadFile(m_DefaultSpriteSetFilename))) {
+ delete m_DefaultSpriteSet;
+ m_DefaultSpriteSet = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ } else return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdTalkDef::GetDefaultSprite(TDirection Dir) {
+ LoadDefaultSprite();
+ if (m_DefaultSprite) return m_DefaultSprite;
+ else if (m_DefaultSpriteSet) return m_DefaultSpriteSet->GetSprite(Dir);
+ else return NULL;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdTalkDef.h b/engines/wintermute/AdTalkDef.h
new file mode 100644
index 0000000000..4702a10fd6
--- /dev/null
+++ b/engines/wintermute/AdTalkDef.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdTalkDef_H__
+#define __WmeAdTalkDef_H__
+
+#include "coll_templ.h"
+#include "BObject.h"
+
+namespace WinterMute {
+class CAdTalkNode;
+class CAdSpriteSet;
+class CAdTalkDef : public CBObject {
+public:
+ char *m_DefaultSpriteSetFilename;
+ CAdSpriteSet *m_DefaultSpriteSet;
+ CBSprite *GetDefaultSprite(TDirection Dir);
+ HRESULT LoadDefaultSprite();
+ DECLARE_PERSISTENT(CAdTalkDef, CBObject)
+
+ CAdTalkDef(CBGame *inGame);
+ virtual ~CAdTalkDef();
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ CBArray<CAdTalkNode *, CAdTalkNode *> m_Nodes;
+ char *m_DefaultSpriteFilename;
+ CBSprite *m_DefaultSprite;
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent = 0);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdTalkHolder.cpp b/engines/wintermute/AdTalkHolder.cpp
new file mode 100644
index 0000000000..228fb77d03
--- /dev/null
+++ b/engines/wintermute/AdTalkHolder.cpp
@@ -0,0 +1,355 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdTalkHolder.h"
+#include "BDynBuffer.h"
+#include "ScValue.h"
+#include "ScScript.h"
+#include "ScStack.h"
+#include "BGame.h"
+#include "BSprite.h"
+#include "PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdTalkHolder, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkHolder::CAdTalkHolder(CBGame *inGame): CAdObject(inGame) {
+ m_Sprite = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkHolder::~CAdTalkHolder() {
+ delete m_Sprite;
+ m_Sprite = NULL;
+
+ int i;
+ for (i = 0; i < m_TalkSprites.GetSize(); i++) delete m_TalkSprites[i];
+ m_TalkSprites.RemoveAll();
+
+ for (i = 0; i < m_TalkSpritesEx.GetSize(); i++) delete m_TalkSpritesEx[i];
+ m_TalkSpritesEx.RemoveAll();
+}
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdTalkHolder::GetTalkStance(char *Stance) {
+ CBSprite *ret = NULL;
+
+
+ // forced stance?
+ if (m_ForcedTalkAnimName && !m_ForcedTalkAnimUsed) {
+ m_ForcedTalkAnimUsed = true;
+ delete m_AnimSprite;
+ m_AnimSprite = new CBSprite(Game, this);
+ if (m_AnimSprite) {
+ HRESULT res = m_AnimSprite->LoadFile(m_ForcedTalkAnimName);
+ if (FAILED(res)) {
+ Game->LOG(res, "CAdTalkHolder::GetTalkStance: error loading talk sprite (object:\"%s\" sprite:\"%s\")", m_Name, m_ForcedTalkAnimName);
+ delete m_AnimSprite;
+ m_AnimSprite = NULL;
+ } else return m_AnimSprite;
+ }
+ }
+
+
+ if (Stance != NULL) {
+ // search special talk stances
+ for (int i = 0; i < m_TalkSpritesEx.GetSize(); i++) {
+ if (scumm_stricmp(m_TalkSpritesEx[i]->m_Name, Stance) == 0) {
+ ret = m_TalkSpritesEx[i];
+ break;
+ }
+ }
+ if (ret == NULL) {
+ // serach generic talk stances
+ for (int i = 0; i < m_TalkSprites.GetSize(); i++) {
+ if (scumm_stricmp(m_TalkSprites[i]->m_Name, Stance) == 0) {
+ ret = m_TalkSprites[i];
+ break;
+ }
+ }
+ }
+ }
+
+ // not a valid stance? get a random one
+ if (ret == NULL) {
+ if (m_TalkSprites.GetSize() < 1) ret = m_Sprite;
+ else {
+ // TODO: remember last
+ int rnd = rand() % m_TalkSprites.GetSize();
+ ret = m_TalkSprites[rnd];
+ }
+ }
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetSprite
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetSprite") == 0) {
+ Stack->CorrectParams(1);
+
+ CScValue *Val = Stack->Pop();
+
+ bool SetCurrent = false;
+ if (m_CurrentSprite && m_CurrentSprite == m_Sprite) SetCurrent = true;
+
+ delete m_Sprite;
+ m_Sprite = NULL;
+
+ if (Val->IsNULL()) {
+ m_Sprite = NULL;
+ if (SetCurrent) m_CurrentSprite = NULL;
+ Stack->PushBool(true);
+ } else {
+ char *Filename = Val->GetString();
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ Script->RuntimeError("SetSprite method failed for file '%s'", Filename);
+ Stack->PushBool(false);
+ } else {
+ m_Sprite = spr;
+ if (SetCurrent) m_CurrentSprite = m_Sprite;
+ Stack->PushBool(true);
+ }
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetSprite") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!m_Sprite || !m_Sprite->m_Filename) Stack->PushNULL();
+ else Stack->PushString(m_Sprite->m_Filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetSpriteObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetSpriteObject") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!m_Sprite) Stack->PushNULL();
+ else Stack->PushNative(m_Sprite, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddTalkSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddTalkSprite") == 0) {
+ Stack->CorrectParams(2);
+
+ char *Filename = Stack->Pop()->GetString();
+ bool Ex = Stack->Pop()->GetBool();
+
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ Stack->PushBool(false);
+ Script->RuntimeError("AddTalkSprite method failed for file '%s'", Filename);
+ } else {
+ if (Ex) m_TalkSpritesEx.Add(spr);
+ else m_TalkSprites.Add(spr);
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // RemoveTalkSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "RemoveTalkSprite") == 0) {
+ Stack->CorrectParams(2);
+
+ char *Filename = Stack->Pop()->GetString();
+ bool Ex = Stack->Pop()->GetBool();
+ int i;
+
+ bool SetCurrent = false;
+ bool SetTemp2 = false;
+
+ if (Ex) {
+ for (i = 0; i < m_TalkSpritesEx.GetSize(); i++) {
+ if (scumm_stricmp(m_TalkSpritesEx[i]->m_Filename, Filename) == 0) {
+ if (m_CurrentSprite == m_TalkSpritesEx[i]) SetCurrent = true;
+ if (m_TempSprite2 == m_TalkSpritesEx[i]) SetTemp2 = true;
+ delete m_TalkSpritesEx[i];
+ m_TalkSpritesEx.RemoveAt(i);
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < m_TalkSprites.GetSize(); i++) {
+ if (scumm_stricmp(m_TalkSprites[i]->m_Filename, Filename) == 0) {
+ if (m_CurrentSprite == m_TalkSprites[i]) SetCurrent = true;
+ if (m_TempSprite2 == m_TalkSprites[i]) SetTemp2 = true;
+ delete m_TalkSprites[i];
+ m_TalkSprites.RemoveAt(i);
+ break;
+ }
+ }
+
+ }
+
+ Stack->PushBool(true);
+ if (SetCurrent) m_CurrentSprite = m_Sprite;
+ if (SetTemp2) m_TempSprite2 = m_Sprite;
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetTalkSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SetTalkSprite") == 0) {
+ Stack->CorrectParams(2);
+
+ char *Filename = Stack->Pop()->GetString();
+ bool Ex = Stack->Pop()->GetBool();
+ bool SetCurrent = false;
+ bool SetTemp2 = false;
+
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ Stack->PushBool(false);
+ Script->RuntimeError("SetTalkSprite method failed for file '%s'", Filename);
+ } else {
+
+ // delete current
+ int i;
+ if (Ex) {
+ for (i = 0; i < m_TalkSpritesEx.GetSize(); i++) {
+ if (m_TalkSpritesEx[i] == m_CurrentSprite) SetCurrent = true;
+ if (m_TalkSpritesEx[i] == m_TempSprite2) SetTemp2 = true;
+ delete m_TalkSpritesEx[i];
+ }
+ m_TalkSpritesEx.RemoveAll();
+ } else {
+ for (i = 0; i < m_TalkSprites.GetSize(); i++) {
+ if (m_TalkSprites[i] == m_CurrentSprite) SetCurrent = true;
+ if (m_TalkSprites[i] == m_TempSprite2) SetTemp2 = true;
+ delete m_TalkSprites[i];
+ }
+ m_TalkSprites.RemoveAll();
+ }
+
+ // set new
+ if (Ex) m_TalkSpritesEx.Add(spr);
+ else m_TalkSprites.Add(spr);
+ Stack->PushBool(true);
+
+ if (SetCurrent) m_CurrentSprite = spr;
+ if (SetTemp2) m_TempSprite2 = spr;
+ }
+ return S_OK;
+ }
+
+ else return CAdObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdTalkHolder::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type (RO)
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("talk-holder");
+ return m_ScValue;
+ }
+
+ else return CAdObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::ScSetProperty(char *Name, CScValue *Value) {
+ /*
+ //////////////////////////////////////////////////////////////////////////
+ // Item
+ //////////////////////////////////////////////////////////////////////////
+ if(strcmp(Name, "Item")==0){
+ SetItem(Value->GetString());
+ return S_OK;
+ }
+
+ else*/ return CAdObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdTalkHolder::ScToString() {
+ return "[talk-holder object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ int i;
+ for (i = 0; i < m_TalkSprites.GetSize(); i++) {
+ if (m_TalkSprites[i]->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "TALK=\"%s\"\n", m_TalkSprites[i]->m_Filename);
+ }
+
+ for (i = 0; i < m_TalkSpritesEx.GetSize(); i++) {
+ if (m_TalkSpritesEx[i]->m_Filename)
+ Buffer->PutTextIndent(Indent + 2, "TALK_SPECIAL=\"%s\"\n", m_TalkSpritesEx[i]->m_Filename);
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::Persist(CBPersistMgr *PersistMgr) {
+ CAdObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Sprite));
+ m_TalkSprites.Persist(PersistMgr);
+ m_TalkSpritesEx.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdTalkNode.cpp b/engines/wintermute/AdTalkNode.cpp
new file mode 100644
index 0000000000..03c0d90609
--- /dev/null
+++ b/engines/wintermute/AdTalkNode.cpp
@@ -0,0 +1,263 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "dcgf.h"
+#include "AdTalkNode.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "BGame.h"
+#include "BSprite.h"
+#include "AdSpriteSet.h"
+#include "utils.h"
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdTalkNode, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkNode::CAdTalkNode(CBGame *inGame): CBBase(inGame) {
+ m_Sprite = NULL;
+ m_SpriteFilename = NULL;
+ m_SpriteSet = NULL;
+ m_SpriteSetFilename = NULL;
+ m_Comment = NULL;
+
+ m_StartTime = m_EndTime = 0;
+ m_PlayToEnd = false;
+ m_PreCache = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkNode::~CAdTalkNode() {
+ delete[] m_SpriteFilename;
+ delete m_Sprite;
+ delete[] m_SpriteSetFilename;
+ delete m_SpriteSet;
+ delete m_Comment;
+ m_SpriteFilename = NULL;
+ m_Sprite = NULL;
+ m_SpriteSetFilename = NULL;
+ m_SpriteSet = NULL;
+ m_Comment = NULL;
+}
+
+
+
+TOKEN_DEF_START
+TOKEN_DEF(ACTION)
+TOKEN_DEF(SPRITESET_FILE)
+TOKEN_DEF(SPRITESET)
+TOKEN_DEF(SPRITE)
+TOKEN_DEF(START_TIME)
+TOKEN_DEF(END_TIME)
+TOKEN_DEF(COMMENT)
+TOKEN_DEF(PRECACHE)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkNode::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ACTION)
+ TOKEN_TABLE(SPRITESET_FILE)
+ TOKEN_TABLE(SPRITESET)
+ TOKEN_TABLE(SPRITE)
+ TOKEN_TABLE(START_TIME)
+ TOKEN_TABLE(END_TIME)
+ TOKEN_TABLE(COMMENT)
+ TOKEN_TABLE(PRECACHE)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_ACTION) {
+ Game->LOG(0, "'ACTION' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ m_EndTime = 0;
+ m_PlayToEnd = false;
+ m_PreCache = false;
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_SPRITE:
+ CBUtils::SetString(&m_SpriteFilename, (char *)params);
+ break;
+
+ case TOKEN_SPRITESET_FILE:
+ CBUtils::SetString(&m_SpriteSetFilename, (char *)params);
+ break;
+
+ case TOKEN_SPRITESET: {
+ delete m_SpriteSet;
+ m_SpriteSet = new CAdSpriteSet(Game);
+ if (!m_SpriteSet || FAILED(m_SpriteSet->LoadBuffer(params, false))) {
+ delete m_SpriteSet;
+ m_SpriteSet = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ }
+ break;
+
+ case TOKEN_START_TIME:
+ parser.ScanStr((char *)params, "%d", &m_StartTime);
+ break;
+
+ case TOKEN_END_TIME:
+ parser.ScanStr((char *)params, "%d", &m_EndTime);
+ break;
+
+ case TOKEN_PRECACHE:
+ parser.ScanStr((char *)params, "%b", &m_PreCache);
+ break;
+
+ case TOKEN_COMMENT:
+ if (Game->m_EditorMode) CBUtils::SetString(&m_Comment, (char *)params);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in ACTION definition");
+ return E_FAIL;
+ }
+
+ if (cmd == PARSERR_GENERIC) {
+ Game->LOG(0, "Error loading ACTION definition");
+ return E_FAIL;
+ }
+
+ if (m_EndTime == 0) m_PlayToEnd = true;
+ else m_PlayToEnd = false;
+
+ if (m_PreCache && m_SpriteFilename) {
+ delete m_Sprite;
+ m_Sprite = new CBSprite(Game);
+ if (!m_Sprite || FAILED(m_Sprite->LoadFile(m_SpriteFilename))) return E_FAIL;
+ }
+
+ if (m_PreCache && m_SpriteSetFilename) {
+ delete m_SpriteSet;
+ m_SpriteSet = new CAdSpriteSet(Game);
+ if (!m_SpriteSet || FAILED(m_SpriteSet->LoadFile(m_SpriteSetFilename))) return E_FAIL;
+ }
+
+
+ return S_OK;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkNode::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(m_Comment));
+ PersistMgr->Transfer(TMEMBER(m_StartTime));
+ PersistMgr->Transfer(TMEMBER(m_EndTime));
+ PersistMgr->Transfer(TMEMBER(m_PlayToEnd));
+ PersistMgr->Transfer(TMEMBER(m_Sprite));
+ PersistMgr->Transfer(TMEMBER(m_SpriteFilename));
+ PersistMgr->Transfer(TMEMBER(m_SpriteSet));
+ PersistMgr->Transfer(TMEMBER(m_SpriteSetFilename));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkNode::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "ACTION {\n");
+ if (m_Comment) Buffer->PutTextIndent(Indent + 2, "COMMENT=\"%s\"\n", m_Comment);
+ Buffer->PutTextIndent(Indent + 2, "START_TIME=%d\n", m_StartTime);
+ if (!m_PlayToEnd) Buffer->PutTextIndent(Indent + 2, "END_TIME=%d\n", m_EndTime);
+ if (m_SpriteFilename) Buffer->PutTextIndent(Indent + 2, "SPRITE=\"%s\"\n", m_SpriteFilename);
+ if (m_SpriteSetFilename) Buffer->PutTextIndent(Indent + 2, "SPRITESET_FILE=\"%s\"\n", m_SpriteSetFilename);
+ else if (m_SpriteSet) m_SpriteSet->SaveAsText(Buffer, Indent + 2);
+ if (m_PreCache) Buffer->PutTextIndent(Indent + 2, "PRECACHE=\"%s\"\n", m_PreCache ? "TRUE" : "FALSE");
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkNode::LoadSprite() {
+ if (m_SpriteFilename && !m_Sprite) {
+ m_Sprite = new CBSprite(Game);
+ if (!m_Sprite || FAILED(m_Sprite->LoadFile(m_SpriteFilename))) {
+ delete m_Sprite;
+ m_Sprite = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ }
+
+ else if (m_SpriteSetFilename && !m_SpriteSet) {
+ m_SpriteSet = new CAdSpriteSet(Game);
+ if (!m_SpriteSet || FAILED(m_SpriteSet->LoadFile(m_SpriteSetFilename))) {
+ delete m_SpriteSet;
+ m_SpriteSet = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ }
+
+ else return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdTalkNode::IsInTimeInterval(uint32 Time, TDirection Dir) {
+ if (Time >= m_StartTime) {
+ if (m_PlayToEnd) {
+ if ((m_SpriteFilename && m_Sprite == NULL) || (m_Sprite && m_Sprite->m_Finished == false)) return true;
+ else if ((m_SpriteSetFilename && m_SpriteSet == NULL) || (m_SpriteSet && m_SpriteSet->GetSprite(Dir) && m_SpriteSet->GetSprite(Dir)->m_Finished == false)) return true;
+ else return false;
+ } else return m_EndTime >= Time;
+ } else return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdTalkNode::GetSprite(TDirection Dir) {
+ LoadSprite();
+ if (m_Sprite) return m_Sprite;
+ else if (m_SpriteSet) return m_SpriteSet->GetSprite(Dir);
+ else return NULL;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdTalkNode.h b/engines/wintermute/AdTalkNode.h
new file mode 100644
index 0000000000..3587cdb57b
--- /dev/null
+++ b/engines/wintermute/AdTalkNode.h
@@ -0,0 +1,63 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdTalkNode_H__
+#define __WmeAdTalkNode_H__
+
+#include "persistent.h"
+#include "BBase.h"
+
+namespace WinterMute {
+class CAdSpriteSet;
+class CBSprite;
+class CAdTalkNode : public CBBase {
+public:
+ char *m_SpriteSetFilename;
+ CAdSpriteSet *m_SpriteSet;
+ CBSprite *GetSprite(TDirection Dir);
+ bool IsInTimeInterval(uint32 Time, TDirection Dir);
+ HRESULT LoadSprite();
+ DECLARE_PERSISTENT(CAdTalkNode, CBBase)
+
+ CAdTalkNode(CBGame *inGame);
+ virtual ~CAdTalkNode();
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent = 0);
+ char *m_SpriteFilename;
+ CBSprite *m_Sprite;
+ uint32 m_StartTime;
+ uint32 m_EndTime;
+ bool m_PlayToEnd;
+ bool m_PreCache;
+ char *m_Comment;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/AdWaypointGroup.cpp b/engines/wintermute/AdWaypointGroup.cpp
new file mode 100644
index 0000000000..265612934f
--- /dev/null
+++ b/engines/wintermute/AdWaypointGroup.cpp
@@ -0,0 +1,260 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "AdWaypointGroup.h"
+#include "BParser.h"
+#include "BDynBuffer.h"
+#include "ScValue.h"
+#include "BGame.h"
+#include "BRegion.h"
+#include "BFileManager.h"
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdWaypointGroup, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdWaypointGroup::CAdWaypointGroup(CBGame *inGame): CBObject(inGame) {
+ m_Active = true;
+ m_EditorSelectedPoint = -1;
+ m_LastMimicScale = -1;
+ m_LastMimicX = m_LastMimicY = INT_MIN;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdWaypointGroup::~CAdWaypointGroup() {
+ Cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdWaypointGroup::Cleanup() {
+ for (int i = 0; i < m_Points.GetSize(); i++)
+ delete m_Points[i];
+ m_Points.RemoveAll();
+ m_EditorSelectedPoint = -1;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::LoadFile(char *Filename) {
+ byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdWaypointGroup::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ m_Filename = new char [strlen(Filename) + 1];
+ strcpy(m_Filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing WAYPOINTS file '%s'", Filename);
+
+
+ delete [] Buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(WAYPOINTS)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(NAME)
+TOKEN_DEF(POINT)
+TOKEN_DEF(EDITOR_SELECTED_POINT)
+TOKEN_DEF(EDITOR_SELECTED)
+TOKEN_DEF(PROPERTY)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::LoadBuffer(byte *Buffer, bool Complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(WAYPOINTS)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(POINT)
+ TOKEN_TABLE(EDITOR_SELECTED_POINT)
+ TOKEN_TABLE(EDITOR_SELECTED)
+ TOKEN_TABLE(PROPERTY)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(Game);
+
+ if (Complete) {
+ if (parser.GetCommand((char **)&Buffer, commands, (char **)&params) != TOKEN_WAYPOINTS) {
+ Game->LOG(0, "'WAYPOINTS' keyword expected.");
+ return E_FAIL;
+ }
+ Buffer = params;
+ }
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ SetName((char *)params);
+ break;
+
+ case TOKEN_POINT: {
+ int x, y;
+ parser.ScanStr((char *)params, "%d,%d", &x, &y);
+ m_Points.Add(new CBPoint(x, y));
+ }
+ break;
+
+ case TOKEN_EDITOR_SELECTED:
+ parser.ScanStr((char *)params, "%b", &m_EditorSelected);
+ break;
+
+ case TOKEN_EDITOR_SELECTED_POINT:
+ parser.ScanStr((char *)params, "%d", &m_EditorSelectedPoint);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in WAYPOINTS definition");
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "WAYPOINTS {\n");
+ Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", m_Name);
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", m_EditorSelected ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED_POINT=%d\n", m_EditorSelectedPoint);
+
+ if (m_ScProp) m_ScProp->SaveAsText(Buffer, Indent + 2);
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ for (int i = 0; i < m_Points.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "POINT {%d,%d}\n", m_Points[i]->x, m_Points[i]->y);
+ }
+
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Active));
+ PersistMgr->Transfer(TMEMBER(m_EditorSelectedPoint));
+ PersistMgr->Transfer(TMEMBER(m_LastMimicScale));
+ PersistMgr->Transfer(TMEMBER(m_LastMimicX));
+ PersistMgr->Transfer(TMEMBER(m_LastMimicY));
+ m_Points.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdWaypointGroup::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("waypoint-group");
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ m_ScValue->SetBool(m_Active);
+ return m_ScValue;
+ }
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::ScSetProperty(char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Active") == 0) {
+ m_Active = Value->GetBool();
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::Mimic(CAdWaypointGroup *Wpt, float Scale, int X, int Y) {
+ if (Scale == m_LastMimicScale && X == m_LastMimicX && Y == m_LastMimicY) return S_OK;
+
+ Cleanup();
+
+ for (int i = 0; i < Wpt->m_Points.GetSize(); i++) {
+ int x, y;
+
+ x = (int)((float)Wpt->m_Points[i]->x * Scale / 100.0f);
+ y = (int)((float)Wpt->m_Points[i]->y * Scale / 100.0f);
+
+ m_Points.Add(new CBPoint(x + X, y + Y));
+ }
+
+ m_LastMimicScale = Scale;
+ m_LastMimicX = X;
+ m_LastMimicY = Y;
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/AdWaypointGroup.h b/engines/wintermute/AdWaypointGroup.h
new file mode 100644
index 0000000000..50992f1387
--- /dev/null
+++ b/engines/wintermute/AdWaypointGroup.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef __WmeAdWaypointGroup_H__
+#define __WmeAdWaypointGroup_H__
+
+#include "BObject.h"
+
+namespace WinterMute {
+class CBPoint;
+class CAdWaypointGroup : public CBObject {
+public:
+ float m_LastMimicScale;
+ int m_LastMimicX;
+ int m_LastMimicY;
+ void Cleanup();
+ HRESULT Mimic(CAdWaypointGroup *Wpt, float Scale = 100.0f, int X = 0, int Y = 0);
+ DECLARE_PERSISTENT(CAdWaypointGroup, CBObject)
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ bool m_Active;
+ CAdWaypointGroup(CBGame *inGame);
+ HRESULT LoadFile(char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual ~CAdWaypointGroup();
+ CBArray<CBPoint *, CBPoint *> m_Points;
+ int m_EditorSelectedPoint;
+ virtual CScValue *ScGetProperty(char *Name);
+ virtual HRESULT ScSetProperty(char *Name, CScValue *Value);
+};
+
+} // end of namespace WinterMute
+
+#endif