aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute/Ad
diff options
context:
space:
mode:
authorEinar Johan Trøan Sømåen2012-06-02 01:17:46 +0200
committerEinar Johan Trøan Sømåen2012-06-02 13:09:20 +0200
commit2317b3538fc5148dc9c7b3d26c2d60fdb06c85e4 (patch)
treecc184367b87a02ac96dfb60fee662efadb67d863 /engines/wintermute/Ad
parentb1e4f58fed4afcc4fcd36eb15cadde19036723fb (diff)
downloadscummvm-rg350-2317b3538fc5148dc9c7b3d26c2d60fdb06c85e4.tar.gz
scummvm-rg350-2317b3538fc5148dc9c7b3d26c2d60fdb06c85e4.tar.bz2
scummvm-rg350-2317b3538fc5148dc9c7b3d26c2d60fdb06c85e4.zip
WINTERMUTE: Move all the Ad files to Ad/
Diffstat (limited to 'engines/wintermute/Ad')
-rw-r--r--engines/wintermute/Ad/AdActor.cpp1339
-rw-r--r--engines/wintermute/Ad/AdActor.h107
-rw-r--r--engines/wintermute/Ad/AdActorDir.cpp52
-rw-r--r--engines/wintermute/Ad/AdActorDir.h46
-rw-r--r--engines/wintermute/Ad/AdEntity.cpp977
-rw-r--r--engines/wintermute/Ad/AdEntity.h67
-rw-r--r--engines/wintermute/Ad/AdGame.cpp2060
-rw-r--r--engines/wintermute/Ad/AdGame.h162
-rw-r--r--engines/wintermute/Ad/AdInventory.cpp119
-rw-r--r--engines/wintermute/Ad/AdInventory.h52
-rw-r--r--engines/wintermute/Ad/AdInventoryBox.cpp373
-rw-r--r--engines/wintermute/Ad/AdInventoryBox.h63
-rw-r--r--engines/wintermute/Ad/AdItem.cpp758
-rw-r--r--engines/wintermute/Ad/AdItem.h70
-rw-r--r--engines/wintermute/Ad/AdLayer.cpp538
-rw-r--r--engines/wintermute/Ad/AdLayer.h58
-rw-r--r--engines/wintermute/Ad/AdNodeState.cpp169
-rw-r--r--engines/wintermute/Ad/AdNodeState.h58
-rw-r--r--engines/wintermute/Ad/AdObject.cpp1203
-rw-r--r--engines/wintermute/Ad/AdObject.h123
-rw-r--r--engines/wintermute/Ad/AdPath.cpp112
-rw-r--r--engines/wintermute/Ad/AdPath.h56
-rw-r--r--engines/wintermute/Ad/AdPathPoint.cpp75
-rw-r--r--engines/wintermute/Ad/AdPathPoint.h50
-rw-r--r--engines/wintermute/Ad/AdRegion.cpp394
-rw-r--r--engines/wintermute/Ad/AdRegion.h58
-rw-r--r--engines/wintermute/Ad/AdResponse.cpp143
-rw-r--r--engines/wintermute/Ad/AdResponse.h61
-rw-r--r--engines/wintermute/Ad/AdResponseBox.cpp645
-rw-r--r--engines/wintermute/Ad/AdResponseBox.h85
-rw-r--r--engines/wintermute/Ad/AdResponseContext.cpp70
-rw-r--r--engines/wintermute/Ad/AdResponseContext.h50
-rw-r--r--engines/wintermute/Ad/AdRotLevel.cpp159
-rw-r--r--engines/wintermute/Ad/AdRotLevel.h49
-rw-r--r--engines/wintermute/Ad/AdScaleLevel.cpp157
-rw-r--r--engines/wintermute/Ad/AdScaleLevel.h50
-rw-r--r--engines/wintermute/Ad/AdScene.cpp2763
-rw-r--r--engines/wintermute/Ad/AdScene.h181
-rw-r--r--engines/wintermute/Ad/AdSceneNode.cpp83
-rw-r--r--engines/wintermute/Ad/AdSceneNode.h54
-rw-r--r--engines/wintermute/Ad/AdSceneState.cpp88
-rw-r--r--engines/wintermute/Ad/AdSceneState.h51
-rw-r--r--engines/wintermute/Ad/AdSentence.cpp317
-rw-r--r--engines/wintermute/Ad/AdSentence.h83
-rw-r--r--engines/wintermute/Ad/AdSpriteSet.cpp313
-rw-r--r--engines/wintermute/Ad/AdSpriteSet.h54
-rw-r--r--engines/wintermute/Ad/AdTalkDef.cpp260
-rw-r--r--engines/wintermute/Ad/AdTalkDef.h58
-rw-r--r--engines/wintermute/Ad/AdTalkHolder.cpp356
-rw-r--r--engines/wintermute/Ad/AdTalkHolder.h57
-rw-r--r--engines/wintermute/Ad/AdTalkNode.cpp263
-rw-r--r--engines/wintermute/Ad/AdTalkNode.h63
-rw-r--r--engines/wintermute/Ad/AdTypes.h93
-rw-r--r--engines/wintermute/Ad/AdWaypointGroup.cpp262
-rw-r--r--engines/wintermute/Ad/AdWaypointGroup.h58
55 files changed, 16065 insertions, 0 deletions
diff --git a/engines/wintermute/Ad/AdActor.cpp b/engines/wintermute/Ad/AdActor.cpp
new file mode 100644
index 0000000000..9b30d16221
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/dctypes.h"
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/BObject.h"
+#include "engines/wintermute/Ad/AdActor.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdScene.h"
+#include "engines/wintermute/Ad/AdEntity.h"
+#include "engines/wintermute/Ad/AdSpriteSet.h"
+#include "engines/wintermute/Ad/AdWaypointGroup.h"
+#include "engines/wintermute/Ad/AdPath.h"
+#include "engines/wintermute/Ad/AdSentence.h"
+#include "engines/wintermute/BObject.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BSound.h"
+#include "engines/wintermute/BRegion.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/utils.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include <math.h>
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdActor, false)
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdActor::CAdActor(CBGame *inGame): CAdTalkHolder(inGame) {
+ _path = new CAdPath(Game);
+
+ _type = OBJECT_ACTOR;
+ _dir = DI_LEFT;
+
+ _walkSprite = NULL;
+ _standSprite = NULL;
+ _turnLeftSprite = NULL;
+ _turnRightSprite = NULL;
+
+ _targetPoint = new CBPoint;
+ _afterWalkDir = DI_NONE;
+
+ _animSprite2 = NULL;
+
+ SetDefaultAnimNames();
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::SetDefaultAnimNames() {
+ _talkAnimName = NULL;
+ CBUtils::SetString(&_talkAnimName, "talk");
+
+ _idleAnimName = NULL;
+ CBUtils::SetString(&_idleAnimName, "idle");
+
+ _walkAnimName = NULL;
+ CBUtils::SetString(&_walkAnimName, "walk");
+
+ _turnLeftAnimName = NULL;
+ CBUtils::SetString(&_turnLeftAnimName, "turnleft");
+
+ _turnRightAnimName = NULL;
+ CBUtils::SetString(&_turnRightAnimName, "turnright");
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CAdActor::~CAdActor() {
+ delete _path;
+ delete _targetPoint;
+ _path = NULL;
+ _targetPoint = NULL;
+
+ delete _walkSprite;
+ delete _standSprite;
+ delete _turnLeftSprite;
+ delete _turnRightSprite;
+ _walkSprite = NULL;
+ _standSprite = NULL;
+ _turnLeftSprite = NULL;
+ _turnRightSprite = NULL;
+
+ _animSprite2 = NULL; // ref only
+
+ for (int i = 0; i < _talkSprites.GetSize(); i++) {
+ delete _talkSprites[i];
+ }
+ _talkSprites.RemoveAll();
+
+ for (int i = 0; i < _talkSpritesEx.GetSize(); i++) {
+ delete _talkSpritesEx[i];
+ }
+ _talkSpritesEx.RemoveAll();
+
+
+ delete[] _talkAnimName;
+ delete[] _idleAnimName;
+ delete[] _walkAnimName;
+ delete[] _turnLeftAnimName;
+ delete[] _turnRightAnimName;
+ _talkAnimName = NULL;
+ _idleAnimName = NULL;
+ _walkAnimName = NULL;
+ _turnLeftAnimName = NULL;
+ _turnRightAnimName = NULL;
+
+ for (int i = 0; i < _anims.GetSize(); i++) {
+ delete _anims[i];
+ _anims[i] = NULL;
+ }
+ _anims.RemoveAll();
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdActor::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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", &_posX);
+ break;
+
+ case TOKEN_Y:
+ parser.ScanStr((char *)params, "%d", &_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", &_zoomable);
+ break;
+
+ case TOKEN_ROTABLE:
+ case TOKEN_ROTATABLE:
+ parser.ScanStr((char *)params, "%b", &_rotatable);
+ break;
+
+ case TOKEN_REGISTRABLE:
+ case TOKEN_INTERACTIVE:
+ parser.ScanStr((char *)params, "%b", &_registrable);
+ break;
+
+ case TOKEN_SHADOWABLE:
+ case TOKEN_COLORABLE:
+ parser.ScanStr((char *)params, "%b", &_shadowable);
+ break;
+
+ case TOKEN_ACTIVE:
+ parser.ScanStr((char *)params, "%b", &_active);
+ break;
+
+ case TOKEN_WALK:
+ delete _walkSprite;
+ _walkSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->_texWalkLifeTime, CACHE_HALF))) cmd = PARSERR_GENERIC;
+ else _walkSprite = spr;
+ break;
+
+ case TOKEN_TALK:
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->_texTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else _talkSprites.Add(spr);
+ break;
+
+ case TOKEN_TALK_SPECIAL:
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->_texTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else _talkSpritesEx.Add(spr);
+ break;
+
+ case TOKEN_STAND:
+ delete _standSprite;
+ _standSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true, AdGame->_texStandLifeTime))) cmd = PARSERR_GENERIC;
+ else _standSprite = spr;
+ break;
+
+ case TOKEN_TURN_LEFT:
+ delete _turnLeftSprite;
+ _turnLeftSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true))) cmd = PARSERR_GENERIC;
+ else _turnLeftSprite = spr;
+ break;
+
+ case TOKEN_TURN_RIGHT:
+ delete _turnRightSprite;
+ _turnRightSprite = NULL;
+ spr = new CAdSpriteSet(Game, this);
+ if (!spr || FAILED(spr->LoadBuffer(params, true))) cmd = PARSERR_GENERIC;
+ else _turnRightSprite = spr;
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursor;
+ _cursor = new CBSprite(Game);
+ if (!_cursor || FAILED(_cursor->LoadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_SOUND_VOLUME:
+ parser.ScanStr((char *)params, "%d", &_sFXVolume);
+ break;
+
+ case TOKEN_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ _scale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_RELATIVE_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ _relativeScale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_SOUND_PANNING:
+ parser.ScanStr((char *)params, "%b", &_autoSoundPanning);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_BLOCKED_REGION: {
+ delete _blockRegion;
+ delete _currentBlockRegion;
+ _blockRegion = NULL;
+ _currentBlockRegion = NULL;
+ CBRegion *rgn = new CBRegion(Game);
+ CBRegion *crgn = new CBRegion(Game);
+ if (!rgn || !crgn || FAILED(rgn->LoadBuffer(params, false))) {
+ delete _blockRegion;
+ delete _currentBlockRegion;
+ _blockRegion = NULL;
+ _currentBlockRegion = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ _blockRegion = rgn;
+ _currentBlockRegion = crgn;
+ _currentBlockRegion->Mimic(_blockRegion);
+ }
+ }
+ break;
+
+ case TOKEN_WAYPOINTS: {
+ delete _wptGroup;
+ delete _currentWptGroup;
+ _wptGroup = NULL;
+ _currentWptGroup = NULL;
+ CAdWaypointGroup *wpt = new CAdWaypointGroup(Game);
+ CAdWaypointGroup *cwpt = new CAdWaypointGroup(Game);
+ if (!wpt || !cwpt || FAILED(wpt->LoadBuffer(params, false))) {
+ delete _wptGroup;
+ delete _currentWptGroup;
+ _wptGroup = NULL;
+ _currentWptGroup = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ _wptGroup = wpt;
+ _currentWptGroup = cwpt;
+ _currentWptGroup->Mimic(_wptGroup);
+ }
+ }
+ break;
+
+ case TOKEN_IGNORE_ITEMS:
+ parser.ScanStr((char *)params, "%b", &_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 _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;
+ }
+ _alphaColor = DRGBA(ar, ag, ab, alpha);
+ _state = _nextState = STATE_READY;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::TurnTo(TDirection dir) {
+ int delta1, delta2, delta3, delta;
+
+ delta1 = dir - _dir;
+ delta2 = dir + NUM_DIRECTIONS - _dir;
+ delta3 = dir - NUM_DIRECTIONS - _dir;
+
+ delta1 = (abs(delta1) <= abs(delta2)) ? delta1 : delta2;
+ delta = (abs(delta1) <= abs(delta3)) ? delta1 : delta3;
+
+ // already there?
+ if (abs(delta) < 2) {
+ _dir = dir;
+ _state = _nextState;
+ _nextState = STATE_READY;
+ return;
+ }
+
+ _targetDir = dir;
+ _state = delta < 0 ? STATE_TURNING_LEFT : STATE_TURNING_RIGHT;
+
+ _tempSprite2 = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::GoTo(int X, int Y, TDirection AfterWalkDir) {
+ _afterWalkDir = AfterWalkDir;
+ if (X == _targetPoint->x && Y == _targetPoint->y && _state == STATE_FOLLOWING_PATH) return;
+
+ _path->Reset();
+ _path->SetReady(false);
+
+ _targetPoint->x = X;
+ _targetPoint->y = Y;
+
+ ((CAdGame *)Game)->_scene->CorrectTargetPoint(_posX, _posY, &_targetPoint->x, &_targetPoint->y, true, this);
+
+ _state = STATE_SEARCHING_PATH;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::Display() {
+ if (_active) UpdateSounds();
+
+ uint32 Alpha;
+ if (_alphaColor != 0) Alpha = _alphaColor;
+ else Alpha = _shadowable ? ((CAdGame *)Game)->_scene->GetAlphaAt(_posX, _posY, true) : 0xFFFFFFFF;
+
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+
+ float Rotate;
+ if (_rotatable) {
+ if (_rotateValid) Rotate = _rotate;
+ else Rotate = ((CAdGame *)Game)->_scene->GetRotationAt(_posX, _posY) + _relativeRotate;
+ } else Rotate = 0.0f;
+
+ if (_active) DisplaySpriteAttachments(true);
+
+ if (_currentSprite && _active) {
+ bool Reg = _registrable;
+ if (_ignoreItems && ((CAdGame *)Game)->_selectedItem) Reg = false;
+
+ _currentSprite->Display(_posX,
+ _posY,
+ Reg ? _registerAlias : NULL,
+ ScaleX,
+ ScaleY,
+ Alpha,
+ Rotate,
+ _blendMode);
+
+ }
+
+ if (_active) DisplaySpriteAttachments(false);
+ if (_active && _partEmitter) _partEmitter->Display();
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::Update() {
+ _currentSprite = NULL;
+
+ if (_state == STATE_READY) {
+ if (_animSprite) {
+ delete _animSprite;
+ _animSprite = NULL;
+ }
+ if (_animSprite2) {
+ _animSprite2 = NULL;
+ }
+ }
+
+ // finished playing animation?
+ if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->_finished) {
+ _state = _nextState;
+ _nextState = STATE_READY;
+ _currentSprite = _animSprite;
+ }
+
+ if (_state == STATE_PLAYING_ANIM_SET && _animSprite2 != NULL && _animSprite2->_finished) {
+ _state = _nextState;
+ _nextState = STATE_READY;
+ _currentSprite = _animSprite2;
+ }
+
+ if (_sentence && _state != STATE_TALKING) _sentence->Finish();
+
+ // default: stand animation
+ if (!_currentSprite) {
+ if (_sprite) _currentSprite = _sprite;
+ else {
+ if (_standSprite) {
+ _currentSprite = _standSprite->GetSprite(_dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(_idleAnimName);
+ if (Anim) _currentSprite = Anim->GetSprite(_dir);
+ }
+ }
+ }
+
+ bool already_moved = false;
+
+ switch (_state) {
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM:
+ _currentSprite = _animSprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM_SET:
+ _currentSprite = _animSprite2;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TURNING_LEFT:
+ if (_tempSprite2 == NULL || _tempSprite2->_finished) {
+ if (_dir > 0) _dir = (TDirection)(_dir - 1);
+ else _dir = (TDirection)(NUM_DIRECTIONS - 1);
+
+ if (_dir == _targetDir) {
+ _tempSprite2 = NULL;
+ _state = _nextState;
+ _nextState = STATE_READY;
+ } else {
+ if (_turnLeftSprite) {
+ _tempSprite2 = _turnLeftSprite->GetSprite(_dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(_turnLeftAnimName);
+ if (Anim) _tempSprite2 = Anim->GetSprite(_dir);
+ }
+
+ if (_tempSprite2) {
+ _tempSprite2->Reset();
+ if (_tempSprite2->_looping) _tempSprite2->_looping = false;
+ }
+ _currentSprite = _tempSprite2;
+ }
+ } else _currentSprite = _tempSprite2;
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TURNING_RIGHT:
+ if (_tempSprite2 == NULL || _tempSprite2->_finished) {
+ _dir = (TDirection)(_dir + 1);
+
+ if ((int)_dir >= (int)NUM_DIRECTIONS) _dir = (TDirection)(0);
+
+ if (_dir == _targetDir) {
+ _tempSprite2 = NULL;
+ _state = _nextState;
+ _nextState = STATE_READY;
+ } else {
+ if (_turnRightSprite) {
+ _tempSprite2 = _turnRightSprite->GetSprite(_dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(_turnRightAnimName);
+ if (Anim) _tempSprite2 = Anim->GetSprite(_dir);
+ }
+
+ if (_tempSprite2) {
+ _tempSprite2->Reset();
+ if (_tempSprite2->_looping) _tempSprite2->_looping = false;
+ }
+ _currentSprite = _tempSprite2;
+ }
+ } else _currentSprite = _tempSprite2;
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_SEARCHING_PATH:
+ // keep asking scene for the path
+ if (((CAdGame *)Game)->_scene->GetPath(CBPoint(_posX, _posY), *_targetPoint, _path, this))
+ _state = STATE_WAITING_PATH;
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_WAITING_PATH:
+ // wait until the scene finished the path
+ if (_path->_ready) FollowPath();
+ break;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_FOLLOWING_PATH:
+ GetNextStep();
+ already_moved = true;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TALKING: {
+ _sentence->Update(_dir);
+ if (_sentence->_currentSprite) _tempSprite2 = _sentence->_currentSprite;
+
+ bool TimeIsUp = (_sentence->_sound && _sentence->_soundStarted && (!_sentence->_sound->IsPlaying() && !_sentence->_sound->IsPaused())) || (!_sentence->_sound && _sentence->_duration <= Game->_timer - _sentence->_startTime);
+ if (_tempSprite2 == NULL || _tempSprite2->_finished || (/*_tempSprite2->_looping &&*/ TimeIsUp)) {
+ if (TimeIsUp) {
+ _sentence->Finish();
+ _tempSprite2 = NULL;
+ _state = _nextState;
+ _nextState = STATE_READY;
+ } else {
+ _tempSprite2 = GetTalkStance(_sentence->GetNextStance());
+ if (_tempSprite2) {
+ _tempSprite2->Reset();
+ _currentSprite = _tempSprite2;
+ ((CAdGame *)Game)->AddSentence(_sentence);
+ }
+ }
+ } else {
+ _currentSprite = _tempSprite2;
+ ((CAdGame *)Game)->AddSentence(_sentence);
+ }
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_READY:
+ if (!_animSprite && !_animSprite2) {
+ if (_sprite) _currentSprite = _sprite;
+ else {
+ if (_standSprite) {
+ _currentSprite = _standSprite->GetSprite(_dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(_idleAnimName);
+ if (Anim) _currentSprite = Anim->GetSprite(_dir);
+ }
+ }
+ }
+ break;
+ default:
+ error("AdActor::Update - Unhandled enum");
+ }
+
+
+ if (_currentSprite && !already_moved) {
+ _currentSprite->GetCurrentFrame(_zoomable ? ((CAdGame *)Game)->_scene->GetZoomAt(_posX, _posY) : 100, _zoomable ? ((CAdGame *)Game)->_scene->GetZoomAt(_posX, _posY) : 100);
+ if (_currentSprite->_changed) {
+ _posX += _currentSprite->_moveX;
+ _posY += _currentSprite->_moveY;
+ AfterMove();
+ }
+ }
+
+ //Game->QuickMessageForm("%s", _currentSprite->_filename);
+
+ UpdateBlockRegion();
+ _ready = (_state == STATE_READY);
+
+ UpdatePartEmitter();
+ UpdateSpriteAttachments();
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::FollowPath() {
+ // skip current position
+ _path->GetFirst();
+ while (_path->GetCurrent() != NULL) {
+ if (_path->GetCurrent()->x != _posX || _path->GetCurrent()->y != _posY) break;
+ _path->GetNext();
+ }
+
+ // are there points to follow?
+ if (_path->GetCurrent() != NULL) {
+ _state = STATE_FOLLOWING_PATH;;
+ InitLine(CBPoint(_posX, _posY), *_path->GetCurrent());
+ } else {
+ if (_afterWalkDir != DI_NONE) TurnTo(_afterWalkDir);
+ else _state = STATE_READY;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::GetNextStep() {
+ if (_walkSprite) {
+ _currentSprite = _walkSprite->GetSprite(_dir);
+ } else {
+ CAdSpriteSet *Anim = GetAnimByName(_walkAnimName);
+ if (Anim) _currentSprite = Anim->GetSprite(_dir);
+ }
+
+ if (!_currentSprite) return;
+
+ _currentSprite->GetCurrentFrame(_zoomable ? ((CAdGame *)Game)->_scene->GetZoomAt(_posX, _posY) : 100, _zoomable ? ((CAdGame *)Game)->_scene->GetZoomAt(_posX, _posY) : 100);
+ if (!_currentSprite->_changed) return;
+
+
+ int MaxStepX, MaxStepY;
+ MaxStepX = abs(_currentSprite->_moveX);
+ MaxStepY = abs(_currentSprite->_moveY);
+
+ MaxStepX = MAX(MaxStepX, MaxStepY);
+ MaxStepX = MAX(MaxStepX, 1);
+
+ while (_pFCount > 0 && MaxStepX >= 0) {
+ _pFX += _pFStepX;
+ _pFY += _pFStepY;
+
+ _pFCount--;
+ MaxStepX--;
+ }
+
+ if (((CAdGame *)Game)->_scene->IsBlockedAt(_pFX, _pFY, true, this)) {
+ if (_pFCount == 0) {
+ _state = _nextState;
+ _nextState = STATE_READY;
+ return;
+ }
+ GoTo(_targetPoint->x, _targetPoint->y);
+ return;
+ }
+
+
+ _posX = (int)_pFX;
+ _posY = (int)_pFY;
+
+ AfterMove();
+
+
+ if (_pFCount == 0) {
+ if (_path->GetNext() == NULL) {
+ _posX = _targetPoint->x;
+ _posY = _targetPoint->y;
+
+ _path->Reset();
+ if (_afterWalkDir != DI_NONE) TurnTo(_afterWalkDir);
+ else {
+ _state = _nextState;
+ _nextState = STATE_READY;
+ }
+ } else InitLine(CBPoint(_posX, _posY), *_path->GetCurrent());
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdActor::InitLine(CBPoint StartPt, CBPoint EndPt) {
+ _pFCount = MAX((abs(EndPt.x - StartPt.x)) , (abs(EndPt.y - StartPt.y)));
+
+ _pFStepX = (double)(EndPt.x - StartPt.x) / _pFCount;
+ _pFStepY = (double)(EndPt.y - StartPt.y) / _pFCount;
+
+ _pFX = StartPt.x;
+ _pFY = StartPt.y;
+
+ int angle = (int)(atan2((double)(EndPt.y - StartPt.y), (double)(EndPt.x - StartPt.x)) * (180 / 3.14));
+
+ _nextState = STATE_FOLLOWING_PATH;
+
+ TurnTo(AngleToDirection(angle));
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const 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->_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->_walkToX == 0 && Ent->_walkToY == 0) GoTo(Ent->_posX, Ent->_posY);
+ else GoTo(Ent->_walkToX, Ent->_walkToY, Ent->_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->_posY - _posY), (double)(obj->_posX - _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(_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);
+ const char *AnimName = Stack->Pop()->GetString();
+
+ bool Found = false;
+ for (int i = 0; i < _anims.GetSize(); i++) {
+ if (scumm_stricmp(_anims[i]->_name, AnimName) == 0) {
+ // invalidate sprites in use
+ if (_anims[i]->ContainsSprite(_tempSprite2)) _tempSprite2 = NULL;
+ if (_anims[i]->ContainsSprite(_currentSprite)) _currentSprite = NULL;
+ if (_anims[i]->ContainsSprite(_animSprite2)) _animSprite2 = NULL;
+
+ delete _anims[i];
+ _anims[i] = NULL;
+ _anims.RemoveAt(i);
+ i--;
+ Found = true;
+ }
+ }
+ Stack->PushBool(Found);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HasAnim
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "HasAnim") == 0) {
+ Stack->CorrectParams(1);
+ const char *AnimName = Stack->Pop()->GetString();
+ Stack->PushBool(GetAnimByName(AnimName) != NULL);
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdActor::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Direction
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Direction") == 0) {
+ _scValue->SetInt(_dir);
+ return _scValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("actor");
+ return _scValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // TalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TalkAnimName") == 0) {
+ _scValue->SetString(_talkAnimName);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkAnimName") == 0) {
+ _scValue->SetString(_walkAnimName);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IdleAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IdleAnimName") == 0) {
+ _scValue->SetString(_idleAnimName);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnLeftAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnLeftAnimName") == 0) {
+ _scValue->SetString(_turnLeftAnimName);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnRightAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnRightAnimName") == 0) {
+ _scValue->SetString(_turnRightAnimName);
+ return _scValue;
+ }
+
+ else return CAdTalkHolder::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::ScSetProperty(const char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Direction
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Direction") == 0) {
+ int dir = Value->GetInt();
+ if (dir >= 0 && dir < NUM_DIRECTIONS) _dir = (TDirection)dir;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TalkAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&_talkAnimName, "talk");
+ else CBUtils::SetString(&_talkAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&_walkAnimName, "walk");
+ else CBUtils::SetString(&_walkAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IdleAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IdleAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&_idleAnimName, "idle");
+ else CBUtils::SetString(&_idleAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnLeftAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnLeftAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&_turnLeftAnimName, "turnleft");
+ else CBUtils::SetString(&_turnLeftAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TurnRightAnimName
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TurnRightAnimName") == 0) {
+ if (Value->IsNULL()) CBUtils::SetString(&_turnRightAnimName, "turnright");
+ else CBUtils::SetString(&_turnRightAnimName, Value->GetString());
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CAdActor::ScToString() {
+ return "[actor object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdActor::GetTalkStance(const char *Stance) {
+ // forced stance?
+ if (_forcedTalkAnimName && !_forcedTalkAnimUsed) {
+ _forcedTalkAnimUsed = true;
+ delete _animSprite;
+ _animSprite = new CBSprite(Game, this);
+ if (_animSprite) {
+ HRESULT res = _animSprite->LoadFile(_forcedTalkAnimName);
+ if (FAILED(res)) {
+ Game->LOG(res, "CAdActor::GetTalkStance: error loading talk sprite (object:\"%s\" sprite:\"%s\")", _name, _forcedTalkAnimName);
+ delete _animSprite;
+ _animSprite = NULL;
+ } else return _animSprite;
+ }
+ }
+
+ // old way
+ if (_talkSprites.GetSize() > 0 || _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(_dir);
+
+ // not - get a random talk
+ if (!Ret) {
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> TalkAnims;
+ for (int i = 0; i < _anims.GetSize(); i++) {
+ if (scumm_stricmp(_anims[i]->_name, _talkAnimName) == 0)
+ TalkAnims.Add(_anims[i]);
+ }
+
+ if (TalkAnims.GetSize() > 0) {
+ int rnd = rand() % TalkAnims.GetSize();
+ Ret = TalkAnims[rnd]->GetSprite(_dir);
+ } else {
+ if (_standSprite) Ret = _standSprite->GetSprite(_dir);
+ else {
+ Anim = GetAnimByName(_idleAnimName);
+ if (Anim) Ret = Anim->GetSprite(_dir);
+ }
+ }
+ }
+ return Ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdActor::GetTalkStanceOld(const char *Stance) {
+ CBSprite *ret = NULL;
+
+ if (Stance != NULL) {
+ // search special stances
+ for (int i = 0; i < _talkSpritesEx.GetSize(); i++) {
+ if (scumm_stricmp(_talkSpritesEx[i]->_name, Stance) == 0) {
+ ret = _talkSpritesEx[i]->GetSprite(_dir);
+ break;
+ }
+ }
+ if (ret == NULL) {
+ // search generic stances
+ for (int i = 0; i < _talkSprites.GetSize(); i++) {
+ if (scumm_stricmp(_talkSprites[i]->_name, Stance) == 0) {
+ ret = _talkSprites[i]->GetSprite(_dir);
+ break;
+ }
+ }
+ }
+ }
+
+ // not a valid stance? get a random one
+ if (ret == NULL) {
+ if (_talkSprites.GetSize() < 1) ret = _standSprite->GetSprite(_dir);
+ else {
+ // TODO: remember last
+ int rnd = rand() % _talkSprites.GetSize();
+ ret = _talkSprites[rnd]->GetSprite(_dir);
+ }
+ }
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::Persist(CBPersistMgr *PersistMgr) {
+ CAdTalkHolder::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER_INT(_dir));
+ PersistMgr->Transfer(TMEMBER(_path));
+ PersistMgr->Transfer(TMEMBER(_pFCount));
+ PersistMgr->Transfer(TMEMBER(_pFStepX));
+ PersistMgr->Transfer(TMEMBER(_pFStepY));
+ PersistMgr->Transfer(TMEMBER(_pFX));
+ PersistMgr->Transfer(TMEMBER(_pFY));
+ PersistMgr->Transfer(TMEMBER(_standSprite));
+ _talkSprites.Persist(PersistMgr);
+ _talkSpritesEx.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER_INT(_targetDir));
+ PersistMgr->Transfer(TMEMBER_INT(_afterWalkDir));
+ PersistMgr->Transfer(TMEMBER(_targetPoint));
+ PersistMgr->Transfer(TMEMBER(_turnLeftSprite));
+ PersistMgr->Transfer(TMEMBER(_turnRightSprite));
+ PersistMgr->Transfer(TMEMBER(_walkSprite));
+
+ PersistMgr->Transfer(TMEMBER(_animSprite2));
+ PersistMgr->Transfer(TMEMBER(_talkAnimName));
+ PersistMgr->Transfer(TMEMBER(_idleAnimName));
+ PersistMgr->Transfer(TMEMBER(_walkAnimName));
+ PersistMgr->Transfer(TMEMBER(_turnLeftAnimName));
+ PersistMgr->Transfer(TMEMBER(_turnRightAnimName));
+
+ _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 (_currentSprite == NULL) {
+ if (_standSprite) _currentSprite = _standSprite->GetSprite(_dir);
+ else {
+ CAdSpriteSet *Anim = GetAnimByName(_idleAnimName);
+ if (Anim) _currentSprite = Anim->GetSprite(_dir);
+ }
+ }
+ // and get height
+ return CAdTalkHolder::GetHeight();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSpriteSet *CAdActor::GetAnimByName(const char *AnimName) {
+ if (!AnimName) return NULL;
+
+ for (int i = 0; i < _anims.GetSize(); i++) {
+ if (scumm_stricmp(_anims[i]->_name, AnimName) == 0) return _anims[i];
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::MergeAnims(const char *AnimsFilename) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ANIMATION)
+ TOKEN_TABLE_END
+
+
+ byte *FileBuffer = Game->_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 _anims.Add(Anim);
+ }
+ break;
+ }
+ }
+ delete [] FileBuffer;
+ return Ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdActor::PlayAnim(const char *Filename) {
+ // if we have an anim with this name, use it
+ CAdSpriteSet *Anim = GetAnimByName(Filename);
+ if (Anim) {
+ _animSprite2 = Anim->GetSprite(_dir);
+ if (_animSprite2) {
+ _animSprite2->Reset();
+ _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/Ad/AdActor.h b/engines/wintermute/Ad/AdActor.h
new file mode 100644
index 0000000000..cbe5e2161e
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADACTOR_H
+#define WINTERMUTE_ADACTOR_H
+
+
+#include "engines/wintermute/dctypes.h" // Added by ClassView
+#include "engines/wintermute/Ad/AdTypes.h" // Added by ClassView
+#include "engines/wintermute/Ad/AdTalkHolder.h"
+#include "engines/wintermute/BPoint.h" // Added by ClassView
+#include "engines/wintermute/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(const char *Stance);
+ virtual void GoTo(int X, int Y, TDirection AfterWalkDir = DI_NONE);
+ CBPoint *_targetPoint;
+ virtual HRESULT Update();
+ virtual HRESULT Display();
+ TDirection _targetDir;
+ TDirection _afterWalkDir;
+ virtual void TurnTo(TDirection dir);
+ CAdPath *_path;
+ CAdSpriteSet *_walkSprite;
+ CAdSpriteSet *_standSprite;
+ CAdSpriteSet *_turnLeftSprite;
+ CAdSpriteSet *_turnRightSprite;
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> _talkSprites;
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> _talkSpritesEx;
+ TDirection _dir;
+ CAdActor(CBGame *inGame/*=NULL*/);
+ virtual ~CAdActor();
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+
+ // new anim system
+ char *_talkAnimName;
+ char *_idleAnimName;
+ char *_walkAnimName;
+ char *_turnLeftAnimName;
+ char *_turnRightAnimName;
+ CBArray<CAdSpriteSet *, CAdSpriteSet *> _anims;
+ virtual HRESULT PlayAnim(const char *Filename);
+ CAdSpriteSet *GetAnimByName(const char *AnimName);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+
+private:
+ HRESULT SetDefaultAnimNames();
+ CBSprite *GetTalkStanceOld(const char *Stance);
+ HRESULT MergeAnims(const char *AnimsFilename);
+ CBSprite *_animSprite2;
+
+ void InitLine(CBPoint StartPt, CBPoint EndPt);
+ void GetNextStep();
+ void FollowPath();
+ double _pFStepX;
+ double _pFStepY;
+ double _pFX;
+ double _pFY;
+ int _pFCount;
+};
+
+} // end of namespace WinterMute
+
+#endif // WINTERMUTE_ADACTOR_H
diff --git a/engines/wintermute/Ad/AdActorDir.cpp b/engines/wintermute/Ad/AdActorDir.cpp
new file mode 100644
index 0000000000..d44cb3dc6d
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/Ad/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/Ad/AdActorDir.h b/engines/wintermute/Ad/AdActorDir.h
new file mode 100644
index 0000000000..6408c51ad9
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADACTORDIR_H
+#define WINTERMUTE_ADACTORDIR_H
+
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/BBase.h"
+
+namespace WinterMute {
+
+class CAdActorDir : public CBBase {
+public:
+ DECLARE_PERSISTENT(CAdActorDir, CBBase)
+ CAdActorDir(CBGame *inGame);
+ virtual ~CAdActorDir(void);
+};
+
+} // end of namespace WinterMute
+
+#endif // WINTERMUTE_ADACTORDIR_H
diff --git a/engines/wintermute/Ad/AdEntity.cpp b/engines/wintermute/Ad/AdEntity.cpp
new file mode 100644
index 0000000000..1e492bbdca
--- /dev/null
+++ b/engines/wintermute/Ad/AdEntity.cpp
@@ -0,0 +1,977 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdEntity.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BActiveRect.h"
+#include "engines/wintermute/BSurfaceStorage.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdScene.h"
+#include "engines/wintermute/BSound.h"
+#include "engines/wintermute/Ad/AdWaypointGroup.h"
+#include "engines/wintermute/BFontStorage.h"
+#include "engines/wintermute/BFont.h"
+#include "engines/wintermute/Ad/AdSentence.h"
+#include "engines/wintermute/BRegion.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "engines/wintermute/utils.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdEntity, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdEntity::CAdEntity(CBGame *inGame): CAdTalkHolder(inGame) {
+ _type = OBJECT_ENTITY;
+ _subtype = ENTITY_NORMAL;
+ _region = NULL;
+ _item = NULL;
+
+ _walkToX = _walkToY = 0;
+ _walkToDir = DI_NONE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdEntity::~CAdEntity() {
+ Game->UnregisterObject(_region);
+
+ delete[] _item;
+ _item = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdEntity::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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", &_posX);
+ break;
+
+ case TOKEN_Y:
+ parser.ScanStr((char *)params, "%d", &_posY);
+ break;
+
+ case TOKEN_SPRITE: {
+ delete _sprite;
+ _sprite = NULL;
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params))) cmd = PARSERR_GENERIC;
+ else _sprite = spr;
+ }
+ break;
+
+ case TOKEN_TALK: {
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, AdGame->_texTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else _talkSprites.Add(spr);
+ }
+ break;
+
+ case TOKEN_TALK_SPECIAL: {
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, AdGame->_texTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else _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", &_zoomable);
+ break;
+
+ case TOKEN_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ _scale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_RELATIVE_SCALE: {
+ int s;
+ parser.ScanStr((char *)params, "%d", &s);
+ _relativeScale = (float)s;
+
+ }
+ break;
+
+ case TOKEN_ROTABLE:
+ case TOKEN_ROTATABLE:
+ parser.ScanStr((char *)params, "%b", &_rotatable);
+ break;
+
+ case TOKEN_REGISTRABLE:
+ case TOKEN_INTERACTIVE:
+ parser.ScanStr((char *)params, "%b", &_registrable);
+ break;
+
+ case TOKEN_SHADOWABLE:
+ case TOKEN_COLORABLE:
+ parser.ScanStr((char *)params, "%b", &_shadowable);
+ break;
+
+ case TOKEN_ACTIVE:
+ parser.ScanStr((char *)params, "%b", &_active);
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursor;
+ _cursor = new CBSprite(Game);
+ if (!_cursor || FAILED(_cursor->LoadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_EDITOR_SELECTED:
+ parser.ScanStr((char *)params, "%b", &_editorSelected);
+ break;
+
+ case TOKEN_REGION: {
+ if (_region) Game->UnregisterObject(_region);
+ _region = NULL;
+ CBRegion *rgn = new CBRegion(Game);
+ if (!rgn || FAILED(rgn->LoadBuffer(params, false))) cmd = PARSERR_GENERIC;
+ else {
+ _region = rgn;
+ Game->RegisterObject(_region);
+ }
+ }
+ break;
+
+ case TOKEN_BLOCKED_REGION: {
+ delete _blockRegion;
+ _blockRegion = NULL;
+ delete _currentBlockRegion;
+ _currentBlockRegion = NULL;
+ CBRegion *rgn = new CBRegion(Game);
+ CBRegion *crgn = new CBRegion(Game);
+ if (!rgn || !crgn || FAILED(rgn->LoadBuffer(params, false))) {
+ delete _blockRegion;
+ _blockRegion = NULL;
+ delete _currentBlockRegion;
+ _currentBlockRegion = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ _blockRegion = rgn;
+ _currentBlockRegion = crgn;
+ _currentBlockRegion->Mimic(_blockRegion);
+ }
+ }
+ break;
+
+ case TOKEN_WAYPOINTS: {
+ delete _wptGroup;
+ _wptGroup = NULL;
+ delete _currentWptGroup;
+ _currentWptGroup = NULL;
+ CAdWaypointGroup *wpt = new CAdWaypointGroup(Game);
+ CAdWaypointGroup *cwpt = new CAdWaypointGroup(Game);
+ if (!wpt || !cwpt || FAILED(wpt->LoadBuffer(params, false))) {
+ delete _wptGroup;
+ _wptGroup = NULL;
+ delete _currentWptGroup;
+ _currentWptGroup = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ _wptGroup = wpt;
+ _currentWptGroup = cwpt;
+ _currentWptGroup->Mimic(_wptGroup);
+ }
+ }
+ break;
+
+ case TOKEN_SCRIPT:
+ AddScript((char *)params);
+ break;
+
+ case TOKEN_SUBTYPE: {
+ if (scumm_stricmp((char *)params, "sound") == 0) {
+ delete _sprite;
+ _sprite = NULL;
+ if (Game->_editorMode) {
+ spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile("entity_sound.sprite"))) cmd = PARSERR_GENERIC;
+ else _sprite = spr;
+ }
+ if (Game->_editorMode) _editorOnly = true;
+ _zoomable = false;
+ _rotatable = false;
+ _registrable = Game->_editorMode;
+ _shadowable = false;
+ _subtype = ENTITY_SOUND;
+ }
+ }
+ break;
+
+ case TOKEN_SOUND:
+ PlaySFX((char *)params, false, false);
+ break;
+
+ case TOKEN_SOUND_START_TIME:
+ parser.ScanStr((char *)params, "%d", &_sFXStart);
+ break;
+
+ case TOKEN_SOUND_VOLUME:
+ parser.ScanStr((char *)params, "%d", &_sFXVolume);
+ break;
+
+ case TOKEN_SOUND_PANNING:
+ parser.ScanStr((char *)params, "%b", &_autoSoundPanning);
+ break;
+
+ case TOKEN_SAVE_STATE:
+ parser.ScanStr((char *)params, "%b", &_saveState);
+ break;
+
+ case TOKEN_PROPERTY:
+ ParseProperty(params, false);
+ break;
+
+ case TOKEN_IGNORE_ITEMS:
+ parser.ScanStr((char *)params, "%b", &_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", &_walkToX);
+ break;
+
+ case TOKEN_WALK_TO_Y:
+ parser.ScanStr((char *)params, "%d", &_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;
+ _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 (_region && _sprite) {
+ Game->LOG(0, "Warning: Entity '%s' has both sprite and region.", _name);
+ }
+
+ UpdatePosition();
+
+ if (alpha != 0 && ar == 0 && ag == 0 && ab == 0) {
+ ar = ag = ab = 255;
+ }
+ _alphaColor = DRGBA(ar, ag, ab, alpha);
+ _state = STATE_READY;
+
+ if (_item && ((CAdGame *)Game)->IsItemTaken(_item)) _active = false;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::Display() {
+ if (_active) {
+ UpdateSounds();
+
+ uint32 Alpha;
+ if (_alphaColor != 0) Alpha = _alphaColor;
+ else Alpha = _shadowable ? ((CAdGame *)Game)->_scene->GetAlphaAt(_posX, _posY) : 0xFFFFFFFF;
+
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+ float Rotate;
+ if (_rotatable) {
+ if (_rotateValid) Rotate = _rotate;
+ else Rotate = ((CAdGame *)Game)->_scene->GetRotationAt(_posX, _posY) + _relativeRotate;
+ } else Rotate = 0.0f;
+
+
+ bool Reg = _registrable;
+ if (_ignoreItems && ((CAdGame *)Game)->_selectedItem) Reg = false;
+
+ if (_region && (Reg || _editorAlwaysRegister)) {
+ Game->_renderer->_rectList.Add(new CBActiveRect(Game, _registerAlias, _region, Game->_offsetX, Game->_offsetY));
+ }
+
+ DisplaySpriteAttachments(true);
+ if (_currentSprite) {
+ _currentSprite->Display(_posX,
+ _posY,
+ (Reg || _editorAlwaysRegister) ? _registerAlias : NULL,
+ ScaleX,
+ ScaleY,
+ Alpha,
+ Rotate,
+ _blendMode);
+ }
+ DisplaySpriteAttachments(false);
+
+ if (_partEmitter) _partEmitter->Display(_region);
+
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::Update() {
+ _currentSprite = NULL;
+
+ if (_state == STATE_READY && _animSprite) {
+ delete _animSprite;
+ _animSprite = NULL;
+ }
+
+ // finished playing animation?
+ if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->_finished) {
+ _state = STATE_READY;
+ _currentSprite = _animSprite;
+ }
+
+ if (_sentence && _state != STATE_TALKING) _sentence->Finish();
+
+ // default: stand animation
+ if (!_currentSprite) _currentSprite = _sprite;
+
+ switch (_state) {
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM:
+ _currentSprite = _animSprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_READY:
+ if (!_animSprite)
+ _currentSprite = _sprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TALKING: {
+ _sentence->Update();
+ if (_sentence->_currentSprite) _tempSprite2 = _sentence->_currentSprite;
+
+ bool TimeIsUp = (_sentence->_sound && _sentence->_soundStarted && (!_sentence->_sound->IsPlaying() && !_sentence->_sound->IsPaused())) || (!_sentence->_sound && _sentence->_duration <= Game->_timer - _sentence->_startTime);
+ if (_tempSprite2 == NULL || _tempSprite2->_finished || (/*_tempSprite2->_looping &&*/ TimeIsUp)) {
+ if (TimeIsUp) {
+ _sentence->Finish();
+ _tempSprite2 = NULL;
+ _state = STATE_READY;
+ } else {
+ _tempSprite2 = GetTalkStance(_sentence->GetNextStance());
+ if (_tempSprite2) {
+ _tempSprite2->Reset();
+ _currentSprite = _tempSprite2;
+ }
+ ((CAdGame *)Game)->AddSentence(_sentence);
+ }
+ } else {
+ _currentSprite = _tempSprite2;
+ ((CAdGame *)Game)->AddSentence(_sentence);
+ }
+ }
+ break;
+ default:
+ error("AdEntity::Update - Unhandled enum");
+ }
+
+
+ if (_currentSprite) {
+ _currentSprite->GetCurrentFrame(_zoomable ? ((CAdGame *)Game)->_scene->GetZoomAt(_posX, _posY) : 100);
+ if (_currentSprite->_changed) {
+ _posX += _currentSprite->_moveX;
+ _posY += _currentSprite->_moveY;
+ }
+ }
+
+ UpdateBlockRegion();
+ _ready = (_state == STATE_READY);
+
+
+ UpdatePartEmitter();
+ UpdateSpriteAttachments();
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // StopSound
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "StopSound") == 0 && _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 (!_region) {
+ _region = new CBRegion(Game);
+ Game->RegisterObject(_region);
+ }
+ if (_region) Stack->PushNative(_region, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteRegion
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DeleteRegion") == 0) {
+ Stack->CorrectParams(0);
+ if (_region) {
+ Game->UnregisterObject(_region);
+ _region = NULL;
+ Stack->PushBool(true);
+ } else Stack->PushBool(false);
+
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdEntity::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type (RO)
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("entity");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Item
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Item") == 0) {
+ if (_item) _scValue->SetString(_item);
+ else _scValue->SetNULL();
+
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Subtype (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Subtype") == 0) {
+ if (_subtype == ENTITY_SOUND)
+ _scValue->SetString("sound");
+ else
+ _scValue->SetString("normal");
+
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToX") == 0) {
+ _scValue->SetInt(_walkToX);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToY") == 0) {
+ _scValue->SetInt(_walkToY);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToDirection
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToDirection") == 0) {
+ _scValue->SetInt((int)_walkToDir);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Region (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Region") == 0) {
+ if (_region) _scValue->SetNative(_region, true);
+ else _scValue->SetNULL();
+ return _scValue;
+ }
+
+ else return CAdTalkHolder::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::ScSetProperty(const char *Name, CScValue *Value) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Item
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Item") == 0) {
+ SetItem(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToX") == 0) {
+ _walkToX = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToY") == 0) {
+ _walkToY = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // WalkToDirection
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "WalkToDirection") == 0) {
+ int Dir = Value->GetInt();
+ if (Dir >= 0 && Dir < NUM_DIRECTIONS) _walkToDir = (TDirection)Dir;
+ return S_OK;
+ }
+
+
+ else return CAdTalkHolder::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const 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", _name);
+ if (_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", _active ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "X=%d\n", _posX);
+ Buffer->PutTextIndent(Indent + 2, "Y=%d\n", _posY);
+ Buffer->PutTextIndent(Indent + 2, "SCALABLE=%s\n", _zoomable ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "INTERACTIVE=%s\n", _registrable ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "COLORABLE=%s\n", _shadowable ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", _editorSelected ? "TRUE" : "FALSE");
+ if (_ignoreItems)
+ Buffer->PutTextIndent(Indent + 2, "IGNORE_ITEMS=%s\n", _ignoreItems ? "TRUE" : "FALSE");
+ if (_rotatable)
+ Buffer->PutTextIndent(Indent + 2, "ROTATABLE=%s\n", _rotatable ? "TRUE" : "FALSE");
+
+ if (!_autoSoundPanning)
+ Buffer->PutTextIndent(Indent + 2, "SOUND_PANNING=%s\n", _autoSoundPanning ? "TRUE" : "FALSE");
+
+ if (!_saveState)
+ Buffer->PutTextIndent(Indent + 2, "SAVE_STATE=%s\n", _saveState ? "TRUE" : "FALSE");
+
+ if (_item && _item[0] != '\0') Buffer->PutTextIndent(Indent + 2, "ITEM=\"%s\"\n", _item);
+
+ Buffer->PutTextIndent(Indent + 2, "WALK_TO_X=%d\n", _walkToX);
+ Buffer->PutTextIndent(Indent + 2, "WALK_TO_Y=%d\n", _walkToY);
+ if (_walkToDir != DI_NONE)
+ Buffer->PutTextIndent(Indent + 2, "WALK_TO_DIR=%d\n", (int)_walkToDir);
+
+ int i;
+
+ for (i = 0; i < _scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ if (_subtype == ENTITY_NORMAL && _sprite && _sprite->_filename)
+ Buffer->PutTextIndent(Indent + 2, "SPRITE=\"%s\"\n", _sprite->_filename);
+
+ if (_subtype == ENTITY_SOUND && _sFX && _sFX->_soundFilename) {
+ Buffer->PutTextIndent(Indent + 2, "SOUND=\"%s\"\n", _sFX->_soundFilename);
+ Buffer->PutTextIndent(Indent + 2, "SOUND_START_TIME=%d\n", _sFXStart);
+ Buffer->PutTextIndent(Indent + 2, "SOUND_VOLUME=%d\n", _sFXVolume);
+ }
+
+
+ if (D3DCOLGetR(_alphaColor) != 0 || D3DCOLGetG(_alphaColor) != 0 || D3DCOLGetB(_alphaColor) != 0)
+ Buffer->PutTextIndent(Indent + 2, "ALPHA_COLOR { %d,%d,%d }\n", D3DCOLGetR(_alphaColor), D3DCOLGetG(_alphaColor), D3DCOLGetB(_alphaColor));
+
+ if (D3DCOLGetA(_alphaColor) != 0)
+ Buffer->PutTextIndent(Indent + 2, "ALPHA = %d\n", D3DCOLGetA(_alphaColor));
+
+ if (_scale >= 0)
+ Buffer->PutTextIndent(Indent + 2, "SCALE = %d\n", (int)_scale);
+
+ if (_relativeScale != 0)
+ Buffer->PutTextIndent(Indent + 2, "RELATIVE_SCALE = %d\n", (int)_relativeScale);
+
+ if (_font && _font->_filename)
+ Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", _font->_filename);
+
+ if (_cursor && _cursor->_filename)
+ Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", _cursor->_filename);
+
+ CAdTalkHolder::SaveAsText(Buffer, Indent + 2);
+
+ if (_region) _region->SaveAsText(Buffer, Indent + 2);
+
+ if (_scProp) _scProp->SaveAsText(Buffer, Indent + 2);
+
+ CAdObject::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdEntity::GetHeight() {
+ if (_region && !_sprite) {
+ return _region->_rect.bottom - _region->_rect.top;
+ } else {
+ if (_currentSprite == NULL) _currentSprite = _sprite;
+ return CAdObject::GetHeight();
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdEntity::UpdatePosition() {
+ if (_region && !_sprite) {
+ _posX = _region->_rect.left + (_region->_rect.right - _region->_rect.left) / 2;
+ _posY = _region->_rect.bottom;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::Persist(CBPersistMgr *PersistMgr) {
+ CAdTalkHolder::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_item));
+ PersistMgr->Transfer(TMEMBER(_region));
+ //PersistMgr->Transfer(TMEMBER(_sprite));
+ PersistMgr->Transfer(TMEMBER_INT(_subtype));
+ _talkSprites.Persist(PersistMgr);
+ _talkSpritesEx.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_walkToX));
+ PersistMgr->Transfer(TMEMBER(_walkToY));
+ PersistMgr->Transfer(TMEMBER_INT(_walkToDir));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdEntity::SetItem(const char *ItemName) {
+ CBUtils::SetString(&_item, ItemName);
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdEntity::SetSprite(const char *Filename) {
+ bool SetCurrent = false;
+ if (_currentSprite == _sprite) {
+ _currentSprite = NULL;
+ SetCurrent = true;
+ }
+
+ delete _sprite;
+ _sprite = NULL;
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile(Filename))) {
+ delete _sprite;
+ _sprite = NULL;
+ return E_FAIL;
+ } else {
+ _sprite = spr;
+ _currentSprite = _sprite;
+ return S_OK;
+ }
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdEntity.h b/engines/wintermute/Ad/AdEntity.h
new file mode 100644
index 0000000000..071ad5ee5d
--- /dev/null
+++ b/engines/wintermute/Ad/AdEntity.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 WINTERMUTE_ADENTITY_H
+#define WINTERMUTE_ADENTITY_H
+
+#include "engines/wintermute/Ad/AdTalkHolder.h"
+
+namespace WinterMute {
+
+class CAdEntity : public CAdTalkHolder {
+public:
+ HRESULT SetSprite(const char *Filename);
+ int _walkToX;
+ int _walkToY;
+ TDirection _walkToDir;
+ void SetItem(const char *ItemName);
+ char *_item;
+ DECLARE_PERSISTENT(CAdEntity, CAdTalkHolder)
+ void UpdatePosition();
+ virtual int GetHeight();
+ CBRegion *_region;
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ virtual HRESULT Update();
+ virtual HRESULT Display();
+ CAdEntity(CBGame *inGame);
+ virtual ~CAdEntity();
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ TEntityType _subtype;
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdGame.cpp b/engines/wintermute/Ad/AdGame.cpp
new file mode 100644
index 0000000000..4de2e70dae
--- /dev/null
+++ b/engines/wintermute/Ad/AdGame.cpp
@@ -0,0 +1,2060 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdResponseBox.h"
+#include "engines/wintermute/Ad/AdInventoryBox.h"
+#include "engines/wintermute/Ad/AdSceneState.h"
+#include "engines/wintermute/PartEmitter.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BSurfaceStorage.h"
+#include "engines/wintermute/BTransitionMgr.h"
+#include "engines/wintermute/BObject.h"
+#include "engines/wintermute/BSound.h"
+#include "engines/wintermute/UIWindow.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/UIEntity.h"
+#include "engines/wintermute/Ad/AdScene.h"
+#include "engines/wintermute/Ad/AdEntity.h"
+#include "engines/wintermute/Ad/AdActor.h"
+#include "engines/wintermute/Ad/AdInventory.h"
+#include "engines/wintermute/Ad/AdResponseContext.h"
+#include "engines/wintermute/Ad/AdItem.h"
+#include "engines/wintermute/BViewport.h"
+#include "engines/wintermute/BFont.h"
+#include "engines/wintermute/scriptables/ScEngine.h"
+#include "engines/wintermute/BStringTable.h"
+#include "engines/wintermute/Ad/AdSentence.h"
+#include "engines/wintermute/Ad/AdResponse.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/utils.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdGame, true)
+
+//////////////////////////////////////////////////////////////////////////
+CAdGame::CAdGame(): CBGame() {
+ _responseBox = NULL;
+ _inventoryBox = NULL;
+
+ _scene = new CAdScene(Game);
+ _scene->SetName("");
+ RegisterObject(_scene);
+
+ _prevSceneName = NULL;
+ _prevSceneFilename = NULL;
+ _scheduledScene = NULL;
+ _scheduledFadeIn = false;
+
+
+ _stateEx = GAME_NORMAL;
+
+ _selectedItem = NULL;
+
+
+ _texItemLifeTime = 10000;
+ _texWalkLifeTime = 10000;
+ _texStandLifeTime = 10000;
+ _texTalkLifeTime = 10000;
+
+ _talkSkipButton = TALK_SKIP_LEFT;
+
+ _sceneViewport = NULL;
+
+ _initialScene = true;
+ _debugStartupScene = NULL;
+ _startupScene = NULL;
+
+ _invObject = new CAdObject(this);
+ _inventoryOwner = _invObject;
+
+ _tempDisableSaveState = false;
+ _itemsFile = NULL;
+
+ _smartItemCursor = false;
+
+ AddSpeechDir("speech");
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdGame::~CAdGame() {
+ Cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::Cleanup() {
+ int i;
+
+ for (i = 0; i < _objects.GetSize(); i++) {
+ UnregisterObject(_objects[i]);
+ _objects[i] = NULL;
+ }
+ _objects.RemoveAll();
+
+
+ for (i = 0; i < _dlgPendingBranches.GetSize(); i++) {
+ delete [] _dlgPendingBranches[i];
+ }
+ _dlgPendingBranches.RemoveAll();
+
+ for (i = 0; i < _speechDirs.GetSize(); i++) {
+ delete [] _speechDirs[i];
+ }
+ _speechDirs.RemoveAll();
+
+
+ UnregisterObject(_scene);
+ _scene = NULL;
+
+ // remove items
+ for (i = 0; i < _items.GetSize(); i++) Game->UnregisterObject(_items[i]);
+ _items.RemoveAll();
+
+
+ // clear remaining inventories
+ delete _invObject;
+ _invObject = NULL;
+
+ for (i = 0; i < _inventories.GetSize(); i++) {
+ delete _inventories[i];
+ }
+ _inventories.RemoveAll();
+
+
+ if (_responseBox) {
+ Game->UnregisterObject(_responseBox);
+ _responseBox = NULL;
+ }
+
+ if (_inventoryBox) {
+ Game->UnregisterObject(_inventoryBox);
+ _inventoryBox = NULL;
+ }
+
+ delete[] _prevSceneName;
+ delete[] _prevSceneFilename;
+ delete[] _scheduledScene;
+ delete[] _debugStartupScene;
+ delete[] _itemsFile;
+ _prevSceneName = NULL;
+ _prevSceneFilename = NULL;
+ _scheduledScene = NULL;
+ _debugStartupScene = NULL;
+ _startupScene = NULL;
+ _itemsFile = NULL;
+
+ delete _sceneViewport;
+ _sceneViewport = NULL;
+
+ for (i = 0; i < _sceneStates.GetSize(); i++) delete _sceneStates[i];
+ _sceneStates.RemoveAll();
+
+ for (i = 0; i < _responsesBranch.GetSize(); i++) delete _responsesBranch[i];
+ _responsesBranch.RemoveAll();
+
+ for (i = 0; i < _responsesGame.GetSize(); i++) delete _responsesGame[i];
+ _responsesGame.RemoveAll();
+
+ return CBGame::Cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::InitLoop() {
+ if (_scheduledScene && _transMgr->IsReady()) {
+ ChangeScene(_scheduledScene, _scheduledFadeIn);
+ delete[] _scheduledScene;
+ _scheduledScene = NULL;
+
+ Game->_activeObject = NULL;
+ }
+
+
+ HRESULT res;
+ res = CBGame::InitLoop();
+ if (FAILED(res)) return res;
+
+ if (_scene) res = _scene->InitLoop();
+
+ _sentences.RemoveAll();
+
+ return res;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddObject(CAdObject *Object) {
+ _objects.Add(Object);
+ return RegisterObject(Object);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::RemoveObject(CAdObject *Object) {
+ // in case the user called Scene.CreateXXX() and Game.DeleteXXX()
+ if (_scene) {
+ HRESULT Res = _scene->RemoveObject(Object);
+ if (SUCCEEDED(Res)) return Res;
+ }
+
+ for (int i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i] == Object) {
+ _objects.RemoveAt(i);
+ break;
+ }
+ }
+ return UnregisterObject(Object);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ChangeScene(const char *Filename, bool FadeIn) {
+ if (_scene == NULL) {
+ _scene = new CAdScene(Game);
+ RegisterObject(_scene);
+ } else {
+ _scene->ApplyEvent("SceneShutdown", true);
+
+ SetPrevSceneName(_scene->_name);
+ SetPrevSceneFilename(_scene->_filename);
+
+ if (!_tempDisableSaveState) _scene->SaveState();
+ _tempDisableSaveState = false;
+ }
+
+ if (_scene) {
+ // reset objects
+ for (int i = 0; i < _objects.GetSize(); i++) _objects[i]->Reset();
+
+ // reset scene properties
+ _scene->_sFXVolume = 100;
+ if (_scene->_scProp) _scene->_scProp->Cleanup();
+
+ HRESULT ret;
+ if (_initialScene && _dEBUG_DebugMode && _debugStartupScene) {
+ _initialScene = false;
+ ret = _scene->LoadFile(_debugStartupScene);
+ } else ret = _scene->LoadFile(Filename);
+
+ if (SUCCEEDED(ret)) {
+ // invalidate references to the original scene
+ for (int i = 0; i < _objects.GetSize(); i++) {
+ _objects[i]->InvalidateCurrRegions();
+ _objects[i]->_stickRegion = NULL;
+ }
+
+ _scene->LoadState();
+ }
+ if (FadeIn) Game->_transMgr->Start(TRANSITION_FADE_IN);
+ return ret;
+ } else return E_FAIL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::AddSentence(CAdSentence *Sentence) {
+ _sentences.Add(Sentence);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DisplaySentences(bool Frozen) {
+ for (int i = 0; i < _sentences.GetSize(); i++) {
+ if (Frozen && _sentences[i]->_freezable) continue;
+ else _sentences[i]->Display();
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::FinishSentences() {
+ for (int i = 0; i < _sentences.GetSize(); i++) {
+ if (_sentences[i]->CanSkip()) {
+ _sentences[i]->_duration = 0;
+ if (_sentences[i]->_sound) _sentences[i]->_sound->Stop();
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // ChangeScene
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "ChangeScene") == 0) {
+ Stack->CorrectParams(3);
+ const 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) _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 < _items.GetSize()) Item = _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();
+ const char *text = Stack->Pop()->GetString();
+ CScValue *val1 = Stack->Pop();
+ CScValue *val2 = Stack->Pop();
+ CScValue *val3 = Stack->Pop();
+ CScValue *val4 = Stack->Pop();
+
+ if (_responseBox) {
+ CAdResponse *res = new CAdResponse(Game);
+ if (res) {
+ res->_iD = id;
+ res->SetText(text);
+ _stringTable->Expand(&res->_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->_responseType = RESPONSE_ONCE;
+ else if (strcmp(Name, "AddResponseOnceGame") == 0) res->_responseType = RESPONSE_ONCE_GAME;
+
+ _responseBox->_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);
+ _responseBox->ClearResponses();
+ _responseBox->ClearButtons();
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetResponse
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetResponse") == 0) {
+ Stack->CorrectParams(1);
+ bool AutoSelectLast = Stack->Pop()->GetBool();
+
+ if (_responseBox) {
+ _responseBox->WeedResponses();
+
+ if (_responseBox->_responses.GetSize() == 0) {
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+
+ if (_responseBox->_responses.GetSize() == 1 && AutoSelectLast) {
+ Stack->PushInt(_responseBox->_responses[0]->_iD);
+ _responseBox->HandleResponse(_responseBox->_responses[0]);
+ _responseBox->ClearResponses();
+ return S_OK;
+ }
+
+ _responseBox->CreateButtons();
+ _responseBox->_waitingScript = Script;
+ Script->WaitForExclusive(_responseBox);
+ _state = GAME_SEMI_FROZEN;
+ _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 (_responseBox) {
+ _responseBox->WeedResponses();
+ Stack->PushInt(_responseBox->_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();
+ Common::String BranchName;
+ if (Val->IsNULL()) {
+ BranchName.format("line%d", Script->_currentLine);
+ } else BranchName = Val->GetString();
+
+ StartDlgBranch(BranchName.c_str(), Script->_filename == NULL ? "" : Script->_filename, Script->_threadEvent == NULL ? "" : Script->_threadEvent);
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // EndDlgBranch
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "EndDlgBranch") == 0) {
+ Stack->CorrectParams(1);
+
+ const char *BranchName = NULL;
+ CScValue *Val = Stack->Pop();
+ if (!Val->IsNULL()) BranchName = Val->GetString();
+ EndDlgBranch(BranchName, Script->_filename == NULL ? "" : Script->_filename, Script->_threadEvent == NULL ? "" : Script->_threadEvent);
+
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetCurrentDlgBranch
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetCurrentDlgBranch") == 0) {
+ Stack->CorrectParams(0);
+
+ if (_dlgPendingBranches.GetSize() > 0) {
+ Stack->PushString(_dlgPendingBranches[_dlgPendingBranches.GetSize() - 1]);
+ } else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TakeItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TakeItem") == 0) {
+ return _invObject->ScCallMethod(Script, Stack, ThisStack, Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DropItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DropItem") == 0) {
+ return _invObject->ScCallMethod(Script, Stack, ThisStack, Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetItem") == 0) {
+ return _invObject->ScCallMethod(Script, Stack, ThisStack, Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HasItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "HasItem") == 0) {
+ return _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 < _inventories.GetSize(); i++) {
+ CAdInventory *Inv = _inventories[i];
+
+ for (int j = 0; j < Inv->_takenItems.GetSize(); j++) {
+ if (val->GetNative() == Inv->_takenItems[j]) {
+ Stack->PushBool(true);
+ return S_OK;
+ } else if (scumm_stricmp(val->GetString(), Inv->_takenItems[j]->_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 (_inventoryBox && _inventoryBox->_window)
+ Stack->PushNative(_inventoryBox->_window, true);
+ else
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetResponsesWindow
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetResponsesWindow") == 0 || strcmp(Name, "GetResponseWindow") == 0) {
+ Stack->CorrectParams(0);
+ if (_responseBox && _responseBox->_window)
+ Stack->PushNative(_responseBox->_window, true);
+ else
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadResponseBox
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadResponseBox") == 0) {
+ Stack->CorrectParams(1);
+ const char *Filename = Stack->Pop()->GetString();
+
+ Game->UnregisterObject(_responseBox);
+ _responseBox = new CAdResponseBox(Game);
+ if (_responseBox && !FAILED(_responseBox->LoadFile(Filename))) {
+ RegisterObject(_responseBox);
+ Stack->PushBool(true);
+ } else {
+ delete _responseBox;
+ _responseBox = NULL;
+ Stack->PushBool(false);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadInventoryBox
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadInventoryBox") == 0) {
+ Stack->CorrectParams(1);
+ const char *Filename = Stack->Pop()->GetString();
+
+ Game->UnregisterObject(_inventoryBox);
+ _inventoryBox = new CAdInventoryBox(Game);
+ if (_inventoryBox && !FAILED(_inventoryBox->LoadFile(Filename))) {
+ RegisterObject(_inventoryBox);
+ Stack->PushBool(true);
+ } else {
+ delete _inventoryBox;
+ _inventoryBox = NULL;
+ Stack->PushBool(false);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LoadItems") == 0) {
+ Stack->CorrectParams(2);
+ const 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);
+ const char *Dir = Stack->Pop()->GetString();
+ Stack->PushBool(SUCCEEDED(AddSpeechDir(Dir)));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // RemoveSpeechDir
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "RemoveSpeechDir") == 0) {
+ Stack->CorrectParams(1);
+ const 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 = _renderer->_width;
+ if (Height <= 0) Height = _renderer->_height;
+
+ if (!_sceneViewport) _sceneViewport = new CBViewport(Game);
+ if (_sceneViewport) _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(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("game");
+ return _scValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Scene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scene") == 0) {
+ if (_scene) _scValue->SetNative(_scene, true);
+ else _scValue->SetNULL();
+
+ return _scValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // SelectedItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SelectedItem") == 0) {
+ //if(_selectedItem) _scValue->SetString(_selectedItem->_name);
+ if (_selectedItem) _scValue->SetNative(_selectedItem, true);
+ else _scValue->SetNULL();
+
+ return _scValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // NumItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumItems") == 0) {
+ return _invObject->ScGetProperty(Name);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SmartItemCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SmartItemCursor") == 0) {
+ _scValue->SetBool(_smartItemCursor);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryVisible
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryVisible") == 0) {
+ _scValue->SetBool(_inventoryBox && _inventoryBox->_visible);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryScrollOffset
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryScrollOffset") == 0) {
+ if (_inventoryBox) _scValue->SetInt(_inventoryBox->_scrollOffset);
+ else _scValue->SetInt(0);
+
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ResponsesVisible (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ResponsesVisible") == 0) {
+ _scValue->SetBool(_stateEx == GAME_WAITING_RESPONSE);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PrevScene / PreviousScene (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PrevScene") == 0 || strcmp(Name, "PreviousScene") == 0) {
+ if (!_prevSceneName) _scValue->SetString("");
+ else _scValue->SetString(_prevSceneName);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PrevSceneFilename / PreviousSceneFilename (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PrevSceneFilename") == 0 || strcmp(Name, "PreviousSceneFilename") == 0) {
+ if (!_prevSceneFilename) _scValue->SetString("");
+ else _scValue->SetString(_prevSceneFilename);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LastResponse (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LastResponse") == 0) {
+ if (!_responseBox || !_responseBox->_lastResponseText) _scValue->SetString("");
+ else _scValue->SetString(_responseBox->_lastResponseText);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LastResponseOrig (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LastResponseOrig") == 0) {
+ if (!_responseBox || !_responseBox->_lastResponseTextOrig) _scValue->SetString("");
+ else _scValue->SetString(_responseBox->_lastResponseTextOrig);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryObject") == 0) {
+ if (_inventoryOwner == _invObject) _scValue->SetNative(this, true);
+ else _scValue->SetNative(_inventoryOwner, true);
+
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TotalNumItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TotalNumItems") == 0) {
+ _scValue->SetInt(_items.GetSize());
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TalkSkipButton
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TalkSkipButton") == 0) {
+ _scValue->SetInt(_talkSkipButton);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ChangingScene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ChangingScene") == 0) {
+ _scValue->SetBool(_scheduledScene != NULL);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StartupScene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StartupScene") == 0) {
+ if (!_startupScene) _scValue->SetNULL();
+ else _scValue->SetString(_startupScene);
+ return _scValue;
+ }
+
+ else return CBGame::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ScSetProperty(const char *Name, CScValue *Value) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // SelectedItem
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SelectedItem") == 0) {
+ if (Value->IsNULL()) _selectedItem = NULL;
+ else {
+ if (Value->IsNative()) {
+ _selectedItem = NULL;
+ for (int i = 0; i < _items.GetSize(); i++) {
+ if (_items[i] == Value->GetNative()) {
+ _selectedItem = (CAdItem *)Value->GetNative();
+ break;
+ }
+ }
+ } else {
+ // try to get by name
+ _selectedItem = GetItemByName(Value->GetString());
+ }
+ }
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SmartItemCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SmartItemCursor") == 0) {
+ _smartItemCursor = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryVisible
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryVisible") == 0) {
+ if (_inventoryBox) _inventoryBox->_visible = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryObject") == 0) {
+ if (_inventoryOwner && _inventoryBox) _inventoryOwner->GetInventory()->_scrollOffset = _inventoryBox->_scrollOffset;
+
+ if (Value->IsNULL()) _inventoryOwner = _invObject;
+ else {
+ CBObject *Obj = (CBObject *)Value->GetNative();
+ if (Obj == this) _inventoryOwner = _invObject;
+ else if (Game->ValidObject(Obj)) _inventoryOwner = (CAdObject *)Obj;
+ }
+
+ if (_inventoryOwner && _inventoryBox) _inventoryBox->_scrollOffset = _inventoryOwner->GetInventory()->_scrollOffset;
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InventoryScrollOffset
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "InventoryScrollOffset") == 0) {
+ if (_inventoryBox) _inventoryBox->_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;
+ _talkSkipButton = (TTalkSkipButton)Val;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StartupScene
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StartupScene") == 0) {
+ if (Value == NULL) {
+ delete[] _startupScene;
+ _startupScene = NULL;
+ } else CBUtils::SetString(&_startupScene, Value->GetString());
+
+ return S_OK;
+ }
+
+ else return CBGame::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::PublishNatives() {
+ if (!_scEngine || !_scEngine->_compilerAvailable) return;
+
+ CBGame::PublishNatives();
+
+ _scEngine->ExtDefineFunction("Actor");
+ _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 (_cursorHidden) return S_OK;
+
+ if (_selectedItem && Game->_state == GAME_RUNNING && _stateEx == GAME_NORMAL && _interactive) {
+ if (_selectedItem->_cursorCombined) {
+ CBSprite *OrigLastCursor = _lastCursor;
+ CBGame::ShowCursor();
+ _lastCursor = OrigLastCursor;
+ }
+ if (_activeObject && _selectedItem->_cursorHover && _activeObject->GetExtendedFlag("usable")) {
+ if (!_smartItemCursor || _activeObject->CanHandleEvent(_selectedItem->_name))
+ return DrawCursor(_selectedItem->_cursorHover);
+ else
+ return DrawCursor(_selectedItem->_cursorNormal);
+ } else return DrawCursor(_selectedItem->_cursorNormal);
+ } else return CBGame::ShowCursor();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::LoadFile(const char *Filename) {
+ byte *Buffer = _fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdGame::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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 _responseBox;
+ _responseBox = new CAdResponseBox(Game);
+ if (_responseBox && !FAILED(_responseBox->LoadFile((char *)params2)))
+ RegisterObject(_responseBox);
+ else {
+ delete _responseBox;
+ _responseBox = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_INVENTORY_BOX:
+ delete _inventoryBox;
+ _inventoryBox = new CAdInventoryBox(Game);
+ if (_inventoryBox && !FAILED(_inventoryBox->LoadFile((char *)params2)))
+ RegisterObject(_inventoryBox);
+ else {
+ delete _inventoryBox;
+ _inventoryBox = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_ITEMS:
+ ItemsFound = true;
+ CBUtils::SetString(&_itemsFile, (char *)params2);
+ if (FAILED(LoadItemsFile(_itemsFile))) {
+ delete[] _itemsFile;
+ _itemsFile = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_TALK_SKIP_BUTTON:
+ if (scumm_stricmp((char *)params2, "right") == 0) _talkSkipButton = TALK_SKIP_RIGHT;
+ else if (scumm_stricmp((char *)params2, "both") == 0) _talkSkipButton = TALK_SKIP_BOTH;
+ else _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 (!_sceneViewport) _sceneViewport = new CBViewport(Game);
+ if (_sceneViewport) _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(&_startupScene, (char *)params2);
+ break;
+
+ case TOKEN_DEBUG_STARTUP_SCENE:
+ CBUtils::SetString(&_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->_saving) Cleanup();
+ CBGame::Persist(PersistMgr);
+
+ _dlgPendingBranches.Persist(PersistMgr);
+
+ _inventories.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_inventoryBox));
+
+ _objects.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_prevSceneName));
+ PersistMgr->Transfer(TMEMBER(_prevSceneFilename));
+
+ PersistMgr->Transfer(TMEMBER(_responseBox));
+ _responsesBranch.Persist(PersistMgr);
+ _responsesGame.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_scene));
+ _sceneStates.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_scheduledFadeIn));
+ PersistMgr->Transfer(TMEMBER(_scheduledScene));
+ PersistMgr->Transfer(TMEMBER(_selectedItem));
+ PersistMgr->Transfer(TMEMBER_INT(_talkSkipButton));
+
+ _sentences.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_sceneViewport));
+ PersistMgr->Transfer(TMEMBER_INT(_stateEx));
+ PersistMgr->Transfer(TMEMBER(_initialScene));
+ PersistMgr->Transfer(TMEMBER(_debugStartupScene));
+
+ PersistMgr->Transfer(TMEMBER(_invObject));
+ PersistMgr->Transfer(TMEMBER(_inventoryOwner));
+ PersistMgr->Transfer(TMEMBER(_tempDisableSaveState));
+ _items.Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_itemsFile));
+
+ _speechDirs.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_smartItemCursor));
+
+ if (!PersistMgr->_saving) _initialScene = false;
+
+ PersistMgr->Transfer(TMEMBER(_startupScene));
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::LoadGame(const 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(const char *Name) {
+ delete[] _prevSceneName;
+ _prevSceneName = NULL;
+ if (Name) {
+ _prevSceneName = new char[strlen(Name) + 1];
+ if (_prevSceneName) strcpy(_prevSceneName, Name);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdGame::SetPrevSceneFilename(const char *Name) {
+ delete[] _prevSceneFilename;
+ _prevSceneFilename = NULL;
+ if (Name) {
+ _prevSceneFilename = new char[strlen(Name) + 1];
+ if (_prevSceneFilename) strcpy(_prevSceneFilename, Name);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ScheduleChangeScene(const char *Filename, bool FadeIn) {
+ delete[] _scheduledScene;
+ _scheduledScene = NULL;
+
+ if (_scene && !_scene->_initialized) return ChangeScene(Filename, FadeIn);
+ else {
+ _scheduledScene = new char [strlen(Filename) + 1];
+ strcpy(_scheduledScene, Filename);
+
+ _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(const char *Filename, bool Merge) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdGame::LoadItemsFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ //_filename = new char [strlen(Filename)+1];
+ //strcpy(_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 (_items.GetSize() > 0) DeleteItem(_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->_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(const 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 < _sceneStates.GetSize(); i++) {
+ if (scumm_stricmp(_sceneStates[i]->_filename, FilenameCor) == 0) {
+ delete [] FilenameCor;
+ return _sceneStates[i];
+ }
+ }
+
+ if (Saving) {
+ CAdSceneState *ret = new CAdSceneState(Game);
+ ret->SetFilename(FilenameCor);
+
+ _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->_parent = Win;
+ Win->_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, const 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->_parent = Win;
+ Win->_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);
+ _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 && _dlgPendingBranches.GetSize() > 0) {
+ Name = _dlgPendingBranches[_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 = _dlgPendingBranches.GetSize() - 1; i >= 0; i--) {
+ if (scumm_stricmp(Name, _dlgPendingBranches[i]) == 0) {
+ StartIndex = i;
+ break;
+ }
+ }
+ if (StartIndex >= 0) {
+ for (i = StartIndex; i < _dlgPendingBranches.GetSize(); i++) {
+ //ClearBranchResponses(_dlgPendingBranches[i]);
+ delete [] _dlgPendingBranches[i];
+ _dlgPendingBranches[i] = NULL;
+ }
+ _dlgPendingBranches.RemoveAt(StartIndex, _dlgPendingBranches.GetSize() - StartIndex);
+ }
+
+ // dialogue is over, forget selected responses
+ if (_dlgPendingBranches.GetSize() == 0) {
+ for (int i = 0; i < _responsesBranch.GetSize(); i++) delete _responsesBranch[i];
+ _responsesBranch.RemoveAll();
+ }
+
+ if (DeleteName) delete [] Name;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ClearBranchResponses(char *Name) {
+ for (int i = 0; i < _responsesBranch.GetSize(); i++) {
+ if (scumm_stricmp(Name, _responsesBranch[i]->_context) == 0) {
+ delete _responsesBranch[i];
+ _responsesBranch.RemoveAt(i);
+ i--;
+ }
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddBranchResponse(int ID) {
+ if (BranchResponseUsed(ID)) return S_OK;
+ CAdResponseContext *r = new CAdResponseContext(Game);
+ r->_iD = ID;
+ r->SetContext(_dlgPendingBranches.GetSize() > 0 ? _dlgPendingBranches[_dlgPendingBranches.GetSize() - 1] : NULL);
+ _responsesBranch.Add(r);
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::BranchResponseUsed(int ID) {
+ char *Context = _dlgPendingBranches.GetSize() > 0 ? _dlgPendingBranches[_dlgPendingBranches.GetSize() - 1] : NULL;
+ for (int i = 0; i < _responsesBranch.GetSize(); i++) {
+ if (_responsesBranch[i]->_iD == ID) {
+ if ((Context == NULL && _responsesBranch[i]->_context == NULL) || scumm_stricmp(Context, _responsesBranch[i]->_context) == 0) return true;
+ }
+ }
+ return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddGameResponse(int ID) {
+ if (GameResponseUsed(ID)) return S_OK;
+ CAdResponseContext *r = new CAdResponseContext(Game);
+ r->_iD = ID;
+ r->SetContext(_dlgPendingBranches.GetSize() > 0 ? _dlgPendingBranches[_dlgPendingBranches.GetSize() - 1] : NULL);
+ _responsesGame.Add(r);
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::GameResponseUsed(int ID) {
+ char *Context = _dlgPendingBranches.GetSize() > 0 ? _dlgPendingBranches[_dlgPendingBranches.GetSize() - 1] : NULL;
+ for (int i = 0; i < _responsesGame.GetSize(); i++) {
+ CAdResponseContext *RespContext = _responsesGame[i];
+ if (RespContext->_iD == ID) {
+ if ((Context == NULL && RespContext->_context == NULL) || ((Context != NULL && RespContext->_context != NULL) && scumm_stricmp(Context, RespContext->_context) == 0)) return true;
+ }
+ }
+ return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ResetResponse(int ID) {
+ char *Context = _dlgPendingBranches.GetSize() > 0 ? _dlgPendingBranches[_dlgPendingBranches.GetSize() - 1] : NULL;
+
+ int i;
+
+ for (i = 0; i < _responsesGame.GetSize(); i++) {
+ if (_responsesGame[i]->_iD == ID) {
+ if ((Context == NULL && _responsesGame[i]->_context == NULL) || scumm_stricmp(Context, _responsesGame[i]->_context) == 0) {
+ delete _responsesGame[i];
+ _responsesGame.RemoveAt(i);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < _responsesBranch.GetSize(); i++) {
+ if (_responsesBranch[i]->_iD == ID) {
+ if ((Context == NULL && _responsesBranch[i]->_context == NULL) || scumm_stricmp(Context, _responsesBranch[i]->_context) == 0) {
+ delete _responsesBranch[i];
+ _responsesBranch.RemoveAt(i);
+ break;
+ }
+ }
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DisplayContent(bool Update, bool DisplayAll) {
+ // init
+ if (Update) InitLoop();
+
+ // fill black
+ _renderer->Fill(0, 0, 0);
+ if (!_editorMode) _renderer->SetScreenViewport();
+
+ // process scripts
+ if (Update) _scEngine->Tick();
+
+ POINT p;
+ GetMousePos(&p);
+
+ _scene->Update();
+ _scene->Display();
+
+
+ // display in-game windows
+ DisplayWindows(true);
+ if (_inventoryBox) _inventoryBox->Display();
+ if (_stateEx == GAME_WAITING_RESPONSE) _responseBox->Display();
+ if (_indicatorDisplay) DisplayIndicator();
+
+
+ if (Update || DisplayAll) {
+ // display normal windows
+ DisplayWindows(false);
+
+ SetActiveObject(Game->_renderer->GetObjectAt(p.x, p.y));
+
+ // textual info
+ DisplaySentences(_state == GAME_FROZEN);
+
+ ShowCursor();
+
+ if (_fader) _fader->Display();
+ _transMgr->Update();
+ }
+
+
+ if (_loadingIcon) {
+ _loadingIcon->Display(_loadingIconX, _loadingIconY);
+ if (!_loadingIconPersistent) {
+ delete _loadingIcon;
+ _loadingIcon = NULL;
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::RegisterInventory(CAdInventory *Inv) {
+ for (int i = 0; i < _inventories.GetSize(); i++) {
+ if (_inventories[i] == Inv) return S_OK;
+ }
+ RegisterObject(Inv);
+ _inventories.Add(Inv);
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::UnregisterInventory(CAdInventory *Inv) {
+ for (int i = 0; i < _inventories.GetSize(); i++) {
+ if (_inventories[i] == Inv) {
+ UnregisterObject(_inventories[i]);
+ _inventories.RemoveAt(i);
+ return S_OK;
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::IsItemTaken(char *ItemName) {
+ int i;
+
+ for (i = 0; i < _inventories.GetSize(); i++) {
+ CAdInventory *Inv = _inventories[i];
+
+ for (int j = 0; j < Inv->_takenItems.GetSize(); j++) {
+ if (scumm_stricmp(ItemName, Inv->_takenItems[j]->_name) == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CAdItem *CAdGame::GetItemByName(const char *Name) {
+ for (int i = 0; i < _items.GetSize(); i++) {
+ if (scumm_stricmp(_items[i]->_name, Name) == 0) return _items[i];
+ }
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::AddItem(CAdItem *Item) {
+ _items.Add(Item);
+ return Game->RegisterObject(Item);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::ResetContent() {
+ int i;
+
+ // clear pending dialogs
+ for (i = 0; i < _dlgPendingBranches.GetSize(); i++) {
+ delete [] _dlgPendingBranches[i];
+ }
+ _dlgPendingBranches.RemoveAll();
+
+
+ // clear inventories
+ for (i = 0; i < _inventories.GetSize(); i++) {
+ _inventories[i]->_takenItems.RemoveAll();
+ }
+
+ // clear scene states
+ for (i = 0; i < _sceneStates.GetSize(); i++) delete _sceneStates[i];
+ _sceneStates.RemoveAll();
+
+ // clear once responses
+ for (i = 0; i < _responsesBranch.GetSize(); i++) delete _responsesBranch[i];
+ _responsesBranch.RemoveAll();
+
+ // clear once game responses
+ for (i = 0; i < _responsesGame.GetSize(); i++) delete _responsesGame[i];
+ _responsesGame.RemoveAll();
+
+ // reload inventory items
+ if (_itemsFile) LoadItemsFile(_itemsFile);
+
+ _tempDisableSaveState = true;
+
+ return CBGame::ResetContent();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DeleteItem(CAdItem *Item) {
+ if (!Item) return E_FAIL;
+
+ if (_selectedItem == Item) _selectedItem = NULL;
+ _scene->HandleItemAssociations(Item->_name, false);
+
+ // remove from all inventories
+ for (int i = 0; i < _inventories.GetSize(); i++) {
+ _inventories[i]->RemoveItem(Item);
+ }
+
+ // remove object
+ for (int i = 0; i < _items.GetSize(); i++) {
+ if (_items[i] == Item) {
+ UnregisterObject(_items[i]);
+ _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 < _speechDirs.GetSize(); i++) {
+ if (scumm_stricmp(_speechDirs[i], Temp) == 0) {
+ delete [] Temp;
+ return S_OK;
+ }
+ }
+ _speechDirs.Add(Temp);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::RemoveSpeechDir(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, "\\");
+
+ bool Found = false;
+ for (int i = 0; i < _speechDirs.GetSize(); i++) {
+ if (scumm_stricmp(_speechDirs[i], Temp) == 0) {
+ delete [] _speechDirs[i];
+ _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 < _speechDirs.GetSize(); i++) {
+ sprintf(Ret, "%s%s.ogg", _speechDirs[i], StringID);
+ CBFile *File = _fileManager->OpenFile(Ret);
+ if (File) {
+ _fileManager->CloseFile(File);
+ return Ret;
+ }
+
+ sprintf(Ret, "%s%s.wav", _speechDirs[i], StringID);
+ File = _fileManager->OpenFile(Ret);
+ if (File) {
+ _fileManager->CloseFile(File);
+ return Ret;
+ }
+ }
+ delete [] Ret;
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdGame::ValidMouse() {
+ POINT Pos;
+ CBPlatform::GetCursorPos(&Pos);
+
+ return _renderer->PointInViewport(&Pos);
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseLeftDown() {
+ if (!ValidMouse()) return S_OK;
+ if (_state == GAME_RUNNING && !_interactive) {
+ if (_talkSkipButton == TALK_SKIP_LEFT || _talkSkipButton == TALK_SKIP_BOTH) {
+ FinishSentences();
+ }
+ return S_OK;
+ }
+
+ if (_activeObject) _activeObject->HandleMouse(MOUSE_CLICK, MOUSE_BUTTON_LEFT);
+
+ bool Handled = _state == GAME_RUNNING && SUCCEEDED(ApplyEvent("LeftClick"));
+ if (!Handled) {
+ if (_activeObject != NULL) {
+ _activeObject->ApplyEvent("LeftClick");
+ } else if (_state == GAME_RUNNING && _scene && _scene->PointInViewport(_mousePos.x, _mousePos.y)) {
+ _scene->ApplyEvent("LeftClick");
+ }
+ }
+
+ if (_activeObject != NULL) Game->_capturedObject = Game->_activeObject;
+ _mouseLeftDown = true;
+ CBPlatform::SetCapture(_renderer->_window);
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseLeftUp() {
+ if (_activeObject) _activeObject->HandleMouse(MOUSE_RELEASE, MOUSE_BUTTON_LEFT);
+
+ CBPlatform::ReleaseCapture();
+ _capturedObject = NULL;
+ _mouseLeftDown = false;
+
+ bool Handled = /*_state==GAME_RUNNING &&*/ SUCCEEDED(ApplyEvent("LeftRelease"));
+ if (!Handled) {
+ if (_activeObject != NULL) {
+ _activeObject->ApplyEvent("LeftRelease");
+ } else if (_state == GAME_RUNNING && _scene && _scene->PointInViewport(_mousePos.x, _mousePos.y)) {
+ _scene->ApplyEvent("LeftRelease");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseLeftDblClick() {
+ if (!ValidMouse()) return S_OK;
+
+ if (_state == GAME_RUNNING && !_interactive) return S_OK;
+
+ if (_activeObject) _activeObject->HandleMouse(MOUSE_DBLCLICK, MOUSE_BUTTON_LEFT);
+
+ bool Handled = _state == GAME_RUNNING && SUCCEEDED(ApplyEvent("LeftDoubleClick"));
+ if (!Handled) {
+ if (_activeObject != NULL) {
+ _activeObject->ApplyEvent("LeftDoubleClick");
+ } else if (_state == GAME_RUNNING && _scene && _scene->PointInViewport(_mousePos.x, _mousePos.y)) {
+ _scene->ApplyEvent("LeftDoubleClick");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseRightDown() {
+ if (!ValidMouse()) return S_OK;
+ if (_state == GAME_RUNNING && !_interactive) {
+ if (_talkSkipButton == TALK_SKIP_RIGHT || _talkSkipButton == TALK_SKIP_BOTH) {
+ FinishSentences();
+ }
+ return S_OK;
+ }
+
+ if ((_state == GAME_RUNNING && !_interactive) || _stateEx == GAME_WAITING_RESPONSE) return S_OK;
+
+ if (_activeObject) _activeObject->HandleMouse(MOUSE_CLICK, MOUSE_BUTTON_RIGHT);
+
+ bool Handled = _state == GAME_RUNNING && SUCCEEDED(ApplyEvent("RightClick"));
+ if (!Handled) {
+ if (_activeObject != NULL) {
+ _activeObject->ApplyEvent("RightClick");
+ } else if (_state == GAME_RUNNING && _scene && _scene->PointInViewport(_mousePos.x, _mousePos.y)) {
+ _scene->ApplyEvent("RightClick");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnMouseRightUp() {
+ if (_activeObject) _activeObject->HandleMouse(MOUSE_RELEASE, MOUSE_BUTTON_RIGHT);
+
+ bool Handled = _state == GAME_RUNNING && SUCCEEDED(ApplyEvent("RightRelease"));
+ if (!Handled) {
+ if (_activeObject != NULL) {
+ _activeObject->ApplyEvent("RightRelease");
+ } else if (_state == GAME_RUNNING && _scene && _scene->PointInViewport(_mousePos.x, _mousePos.y)) {
+ _scene->ApplyEvent("RightRelease");
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::DisplayDebugInfo() {
+ char str[100];
+ if (Game->_dEBUG_DebugMode) {
+ sprintf(str, "Mouse: %d, %d (scene: %d, %d)", _mousePos.x, _mousePos.y, _mousePos.x + _scene->GetOffsetLeft(), _mousePos.y + _scene->GetOffsetTop());
+ _systemFont->DrawText((byte *)str, 0, 90, _renderer->_width, TAL_RIGHT);
+
+ sprintf(str, "Scene: %s (prev: %s)", (_scene && _scene->_name) ? _scene->_name : "???", _prevSceneName ? _prevSceneName : "???");
+ _systemFont->DrawText((byte *)str, 0, 110, _renderer->_width, TAL_RIGHT);
+ }
+ return CBGame::DisplayDebugInfo();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdGame::OnScriptShutdown(CScScript *Script) {
+ if (_responseBox && _responseBox->_waitingScript == Script)
+ _responseBox->_waitingScript = NULL;
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdGame.h b/engines/wintermute/Ad/AdGame.h
new file mode 100644
index 0000000000..8c146d1af3
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADGAME_H
+#define WINTERMUTE_ADGAME_H
+
+#include "engines/wintermute/Ad/AdTypes.h"
+#include "engines/wintermute/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 _smartItemCursor;
+
+ CBArray<char *, char *> _speechDirs;
+ HRESULT AddSpeechDir(const char *Dir);
+ HRESULT RemoveSpeechDir(const char *Dir);
+ char *FindSpeechFile(char *StringID);
+
+ HRESULT DeleteItem(CAdItem *Item);
+ char *_itemsFile;
+ bool _tempDisableSaveState;
+ virtual HRESULT ResetContent();
+ HRESULT AddItem(CAdItem *Item);
+ CAdItem *GetItemByName(const char *Name);
+ CBArray<CAdItem *, CAdItem *> _items;
+ CAdObject *_inventoryOwner;
+ bool IsItemTaken(char *ItemName);
+ HRESULT RegisterInventory(CAdInventory *Inv);
+ HRESULT UnregisterInventory(CAdInventory *Inv);
+
+ CAdObject *_invObject;
+ CBArray<CAdInventory *, CAdInventory *> _inventories;
+ virtual HRESULT DisplayContent(bool Update = true, bool DisplayAll = false);
+ char *_debugStartupScene;
+ char *_startupScene;
+ bool _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, const char *Name);
+
+ CAdSceneState *GetSceneState(const char *Filename, bool Saving);
+ CBViewport *_sceneViewport;
+ int _texItemLifeTime;
+ int _texWalkLifeTime;
+ int _texStandLifeTime;
+ int _texTalkLifeTime;
+
+ TTalkSkipButton _talkSkipButton;
+
+ virtual HRESULT GetVersion(byte *VerMajor, byte *VerMinor, byte *ExtMajor, byte *ExtMinor);
+ HRESULT ScheduleChangeScene(const char *Filename, bool FadeIn);
+ char *_scheduledScene;
+ bool _scheduledFadeIn;
+ void SetPrevSceneName(const char *Name);
+ void SetPrevSceneFilename(const char *Name);
+ char *_prevSceneName;
+ char *_prevSceneFilename;
+ virtual HRESULT LoadGame(const char *Filename);
+ CAdItem *_selectedItem;
+ HRESULT Cleanup();
+ DECLARE_PERSISTENT(CAdGame, CBGame)
+
+ void FinishSentences();
+ HRESULT ShowCursor();
+ TGameStateEx _stateEx;
+ CAdResponseBox *_responseBox;
+ CAdInventoryBox *_inventoryBox;
+ HRESULT DisplaySentences(bool Frozen);
+ void AddSentence(CAdSentence *Sentence);
+ HRESULT ChangeScene(const char *Filename, bool FadeIn);
+ HRESULT RemoveObject(CAdObject *Object);
+ HRESULT AddObject(CAdObject *Object);
+ CAdScene *_scene;
+ HRESULT InitLoop();
+ CAdGame();
+ virtual ~CAdGame();
+ CBArray<CAdObject *, CAdObject *> _objects;
+ CBArray<CAdSentence *, CAdSentence *> _sentences;
+
+ CBArray<CAdSceneState *, CAdSceneState *> _sceneStates;
+ CBArray<char *, char *> _dlgPendingBranches;
+
+ CBArray<CAdResponseContext *, CAdResponseContext *> _responsesBranch;
+ CBArray<CAdResponseContext *, CAdResponseContext *> _responsesGame;
+
+ virtual HRESULT LoadFile(const char *Filename);
+ virtual HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+
+ HRESULT LoadItemsFile(const 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(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ bool ValidMouse();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdInventory.cpp b/engines/wintermute/Ad/AdInventory.cpp
new file mode 100644
index 0000000000..693f09bcf6
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/Ad/AdInventory.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdItem.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdInventory, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventory::CAdInventory(CBGame *inGame): CBObject(inGame) {
+ _scrollOffset = 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventory::~CAdInventory() {
+ _takenItems.RemoveAll(); // ref only
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventory::InsertItem(const char *Name, const 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 < _takenItems.GetSize(); i++) {
+ if (scumm_stricmp(_takenItems[i]->_name, Name) == 0) {
+ _takenItems.RemoveAt(i);
+ i--;
+ continue;
+ }
+ if (InsertAfter && scumm_stricmp(_takenItems[i]->_name, InsertAfter) == 0) InsertIndex = i + 1;
+ }
+
+
+ if (InsertIndex == -1) _takenItems.Add(item);
+ else _takenItems.InsertAt(InsertIndex, item);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventory::RemoveItem(const char *Name) {
+ if (Name == NULL) return E_FAIL;
+
+ for (int i = 0; i < _takenItems.GetSize(); i++) {
+ if (scumm_stricmp(_takenItems[i]->_name, Name) == 0) {
+ if (((CAdGame *)Game)->_selectedItem == _takenItems[i])((CAdGame *)Game)->_selectedItem = NULL;
+ _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 < _takenItems.GetSize(); i++) {
+ if (_takenItems[i] == Item) {
+ if (((CAdGame *)Game)->_selectedItem == _takenItems[i])((CAdGame *)Game)->_selectedItem = NULL;
+ _takenItems.RemoveAt(i);
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventory::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ _takenItems.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_scrollOffset));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdInventory.h b/engines/wintermute/Ad/AdInventory.h
new file mode 100644
index 0000000000..b6f0c6399a
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADINVENTORY_H
+#define WINTERMUTE_ADINVENTORY_H
+
+#include "engines/wintermute/BObject.h"
+
+namespace WinterMute {
+
+class CAdItem;
+
+class CAdInventory : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdInventory, CBObject)
+ HRESULT RemoveItem(const char *Name);
+ HRESULT RemoveItem(CAdItem *Item);
+ HRESULT InsertItem(const char *Name, const char *InsertAfter = NULL);
+ CAdInventory(CBGame *inGame);
+ virtual ~CAdInventory();
+ CBArray<CAdItem *, CAdItem *> _takenItems;
+ int _scrollOffset;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdInventoryBox.cpp b/engines/wintermute/Ad/AdInventoryBox.cpp
new file mode 100644
index 0000000000..5de9f54493
--- /dev/null
+++ b/engines/wintermute/Ad/AdInventoryBox.cpp
@@ -0,0 +1,373 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdInventoryBox.h"
+#include "engines/wintermute/Ad/AdInventory.h"
+#include "engines/wintermute/Ad/AdItem.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/BViewport.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/UIButton.h"
+#include "engines/wintermute/UIWindow.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+//#include <cmath>
+
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdInventoryBox, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventoryBox::CAdInventoryBox(CBGame *inGame): CBObject(inGame) {
+ CBPlatform::SetRectEmpty(&_itemsArea);
+ _scrollOffset = 0;
+ _spacing = 0;
+ _itemWidth = _itemHeight = 50;
+ _scrollBy = 1;
+
+ _window = NULL;
+ _closeButton = NULL;
+
+ _hideSelected = false;
+
+ _visible = false;
+ _exclusive = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventoryBox::~CAdInventoryBox() {
+ Game->UnregisterObject(_window);
+ _window = NULL;
+
+ delete _closeButton;
+ _closeButton = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::Listen(CBScriptHolder *param1, uint32 param2) {
+ CUIObject *obj = (CUIObject *)param1;
+
+ switch (obj->_type) {
+ case UI_BUTTON:
+ if (scumm_stricmp(obj->_name, "close") == 0) {
+ _visible = false;
+ } else if (scumm_stricmp(obj->_name, "prev") == 0) {
+ _scrollOffset -= _scrollBy;
+ _scrollOffset = MAX(_scrollOffset, 0);
+ } else if (scumm_stricmp(obj->_name, "next") == 0) {
+ _scrollOffset += _scrollBy;
+ } else return CBObject::Listen(param1, param2);
+ break;
+ default:
+ error("CAdInventoryBox::Listen - Unhandled enum");
+ break;
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::Display() {
+ CAdGame *AdGame = (CAdGame *)Game;
+
+ if (!_visible) return S_OK;
+
+ int ItemsX, ItemsY;
+ ItemsX = floor((float)((_itemsArea.right - _itemsArea.left + _spacing) / (_itemWidth + _spacing)));
+ ItemsY = floor((float)((_itemsArea.bottom - _itemsArea.top + _spacing) / (_itemHeight + _spacing)));
+
+ if (_window) {
+ _window->EnableWidget("prev", _scrollOffset > 0);
+ _window->EnableWidget("next", _scrollOffset + ItemsX * ItemsY < AdGame->_inventoryOwner->GetInventory()->_takenItems.GetSize());
+ }
+
+
+ if (_closeButton) {
+ _closeButton->_posX = _closeButton->_posY = 0;
+ _closeButton->_width = Game->_renderer->_width;
+ _closeButton->_height = Game->_renderer->_height;
+
+ _closeButton->Display();
+ }
+
+
+ // display window
+ RECT rect = _itemsArea;
+ if (_window) {
+ CBPlatform::OffsetRect(&rect, _window->_posX, _window->_posY);
+ _window->Display();
+ }
+
+ // display items
+ if (_window && _window->_alphaColor != 0) Game->_renderer->_forceAlphaColor = _window->_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 = _scrollOffset + j * ItemsX + i;
+ if (ItemIndex >= 0 && ItemIndex < AdGame->_inventoryOwner->GetInventory()->_takenItems.GetSize()) {
+ CAdItem *item = AdGame->_inventoryOwner->GetInventory()->_takenItems[ItemIndex];
+ if (item != ((CAdGame *)Game)->_selectedItem || !_hideSelected) {
+ item->Update();
+ item->Display(xxx, yyy);
+ }
+ }
+
+ xxx += (_itemWidth + _spacing);
+ }
+ yyy += (_itemHeight + _spacing);
+ }
+ if (_window && _window->_alphaColor != 0) Game->_renderer->_forceAlphaColor = 0;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdInventoryBox::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdInventoryBox::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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;
+
+ _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:
+ delete _window;
+ _window = new CUIWindow(Game);
+ if (!_window || FAILED(_window->LoadBuffer(params, false))) {
+ delete _window;
+ _window = NULL;
+ cmd = PARSERR_GENERIC;
+ } else Game->RegisterObject(_window);
+ break;
+
+ case TOKEN_AREA:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &_itemsArea.left, &_itemsArea.top, &_itemsArea.right, &_itemsArea.bottom);
+ break;
+
+ case TOKEN_EXCLUSIVE:
+ parser.ScanStr((char *)params, "%b", &_exclusive);
+ break;
+
+ case TOKEN_HIDE_SELECTED:
+ parser.ScanStr((char *)params, "%b", &_hideSelected);
+ break;
+
+ case TOKEN_ALWAYS_VISIBLE:
+ parser.ScanStr((char *)params, "%b", &always_visible);
+ break;
+
+ case TOKEN_SPACING:
+ parser.ScanStr((char *)params, "%d", &_spacing);
+ break;
+
+ case TOKEN_ITEM_WIDTH:
+ parser.ScanStr((char *)params, "%d", &_itemWidth);
+ break;
+
+ case TOKEN_ITEM_HEIGHT:
+ parser.ScanStr((char *)params, "%d", &_itemHeight);
+ break;
+
+ case TOKEN_SCROLL_BY:
+ parser.ScanStr((char *)params, "%d", &_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 (_exclusive) {
+ delete _closeButton;
+ _closeButton = new CUIButton(Game);
+ if (_closeButton) {
+ _closeButton->SetName("close");
+ _closeButton->SetListener(this, _closeButton, 0);
+ _closeButton->_parent = _window;
+ }
+ }
+
+ _visible = always_visible;
+
+ if (_window) {
+ for (int i = 0; i < _window->_widgets.GetSize(); i++) {
+ if (!_window->_widgets[i]->_listenerObject)
+ _window->_widgets[i]->SetListener(this, _window->_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", _name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+
+ Buffer->PutTextIndent(Indent + 2, "AREA { %d, %d, %d, %d }\n", _itemsArea.left, _itemsArea.top, _itemsArea.right, _itemsArea.bottom);
+
+ Buffer->PutTextIndent(Indent + 2, "EXCLUSIVE=%s\n", _exclusive ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "HIDE_SELECTED=%s\n", _hideSelected ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "ALWAYS_VISIBLE=%s\n", _visible ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "SPACING=%d\n", _spacing);
+ Buffer->PutTextIndent(Indent + 2, "ITEM_WIDTH=%d\n", _itemWidth);
+ Buffer->PutTextIndent(Indent + 2, "ITEM_HEIGHT=%d\n", _itemHeight);
+ Buffer->PutTextIndent(Indent + 2, "SCROLL_BY=%d\n", _scrollBy);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // window
+ if (_window) _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(_closeButton));
+ PersistMgr->Transfer(TMEMBER(_hideSelected));
+ PersistMgr->Transfer(TMEMBER(_itemHeight));
+ PersistMgr->Transfer(TMEMBER(_itemsArea));
+ PersistMgr->Transfer(TMEMBER(_itemWidth));
+ PersistMgr->Transfer(TMEMBER(_scrollBy));
+ PersistMgr->Transfer(TMEMBER(_scrollOffset));
+ PersistMgr->Transfer(TMEMBER(_spacing));
+ PersistMgr->Transfer(TMEMBER(_visible));
+ PersistMgr->Transfer(TMEMBER(_window));
+ PersistMgr->Transfer(TMEMBER(_exclusive));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdInventoryBox.h b/engines/wintermute/Ad/AdInventoryBox.h
new file mode 100644
index 0000000000..b7838607d2
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADINVENTORYBOX_H
+#define WINTERMUTE_ADINVENTORYBOX_H
+
+#include "engines/wintermute/BObject.h"
+
+namespace WinterMute {
+class CUIButton;
+class CUIWindow;
+
+class CAdInventoryBox : public CBObject {
+public:
+ bool _hideSelected;
+ DECLARE_PERSISTENT(CAdInventoryBox, CBObject)
+ bool _exclusive;
+ int _scrollBy;
+ int _itemHeight;
+ int _itemWidth;
+ bool _visible;
+ virtual HRESULT Display();
+ CUIButton *_closeButton;
+ int _spacing;
+ int _scrollOffset;
+ RECT _itemsArea;
+ HRESULT Listen(CBScriptHolder *param1, uint32 param2);
+ CUIWindow *_window;
+ CAdInventoryBox(CBGame *inGame);
+ virtual ~CAdInventoryBox();
+ HRESULT LoadFile(const 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/Ad/AdItem.cpp b/engines/wintermute/Ad/AdItem.cpp
new file mode 100644
index 0000000000..efd655c500
--- /dev/null
+++ b/engines/wintermute/Ad/AdItem.cpp
@@ -0,0 +1,758 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdItem.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdSentence.h"
+#include "engines/wintermute/BFontStorage.h"
+#include "engines/wintermute/BFont.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BSound.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/utils.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdItem, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdItem::CAdItem(CBGame *inGame): CAdTalkHolder(inGame) {
+ _spriteHover = NULL;
+ _cursorNormal = _cursorHover = NULL;
+
+ _cursorCombined = true;
+ _inInventory = false;
+
+ _displayAmount = false;
+ _amount = 0;
+ _amountOffsetX = 0;
+ _amountOffsetY = 0;
+ _amountAlign = TAL_RIGHT;
+ _amountString = NULL;
+
+ _state = STATE_READY;
+
+ _movable = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdItem::~CAdItem() {
+ delete _spriteHover;
+ delete _cursorNormal;
+ delete _cursorHover;
+ _spriteHover = NULL;
+ _cursorNormal = NULL;
+ _cursorHover = NULL;
+
+ delete[] _amountString;
+ _amountString = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdItem::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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 _sprite;
+ _sprite = new CBSprite(Game, this);
+ if (!_sprite || FAILED(_sprite->LoadFile((char *)params, ((CAdGame *)Game)->_texItemLifeTime))) {
+ delete _sprite;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE_HOVER:
+ case TOKEN_SPRITE_HOVER:
+ delete _spriteHover;
+ _spriteHover = new CBSprite(Game, this);
+ if (!_spriteHover || FAILED(_spriteHover->LoadFile((char *)params, ((CAdGame *)Game)->_texItemLifeTime))) {
+ delete _spriteHover;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_AMOUNT:
+ parser.ScanStr((char *)params, "%d", &_amount);
+ break;
+
+ case TOKEN_DISPLAY_AMOUNT:
+ parser.ScanStr((char *)params, "%b", &_displayAmount);
+ break;
+
+ case TOKEN_AMOUNT_OFFSET_X:
+ parser.ScanStr((char *)params, "%d", &_amountOffsetX);
+ break;
+
+ case TOKEN_AMOUNT_OFFSET_Y:
+ parser.ScanStr((char *)params, "%d", &_amountOffsetY);
+ break;
+
+ case TOKEN_AMOUNT_ALIGN:
+ if (scumm_stricmp((char *)params, "left") == 0) _amountAlign = TAL_LEFT;
+ else if (scumm_stricmp((char *)params, "right") == 0) _amountAlign = TAL_RIGHT;
+ else _amountAlign = TAL_CENTER;
+ break;
+
+ case TOKEN_AMOUNT_STRING:
+ CBUtils::SetString(&_amountString, (char *)params);
+ break;
+
+ case TOKEN_TALK: {
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, ((CAdGame *)Game)->_texTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else _talkSprites.Add(spr);
+ }
+ break;
+
+ case TOKEN_TALK_SPECIAL: {
+ CBSprite *spr = new CBSprite(Game, this);
+ if (!spr || FAILED(spr->LoadFile((char *)params, ((CAdGame *)Game)->_texTalkLifeTime))) cmd = PARSERR_GENERIC;
+ else _talkSpritesEx.Add(spr);
+ }
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursorNormal;
+ _cursorNormal = new CBSprite(Game);
+ if (!_cursorNormal || FAILED(_cursorNormal->LoadFile((char *)params, ((CAdGame *)Game)->_texItemLifeTime))) {
+ delete _cursorNormal;
+ _cursorNormal = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_CURSOR_HOVER:
+ delete _cursorHover;
+ _cursorHover = new CBSprite(Game);
+ if (!_cursorHover || FAILED(_cursorHover->LoadFile((char *)params, ((CAdGame *)Game)->_texItemLifeTime))) {
+ delete _cursorHover;
+ _cursorHover = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_CURSOR_COMBINED:
+ parser.ScanStr((char *)params, "%b", &_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;
+ }
+ _alphaColor = DRGBA(ar, ag, ab, alpha);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::Update() {
+ _currentSprite = NULL;
+
+ if (_state == STATE_READY && _animSprite) {
+ delete _animSprite;
+ _animSprite = NULL;
+ }
+
+ // finished playing animation?
+ if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->_finished) {
+ _state = STATE_READY;
+ _currentSprite = _animSprite;
+ }
+
+ if (_sentence && _state != STATE_TALKING) _sentence->Finish();
+
+ // default: stand animation
+ if (!_currentSprite) _currentSprite = _sprite;
+
+ switch (_state) {
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_PLAYING_ANIM:
+ _currentSprite = _animSprite;
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_READY:
+ if (!_animSprite) {
+ if (Game->_activeObject == this && _spriteHover) _currentSprite = _spriteHover;
+ else _currentSprite = _sprite;
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case STATE_TALKING: {
+ _sentence->Update();
+ if (_sentence->_currentSprite) _tempSprite2 = _sentence->_currentSprite;
+
+ bool TimeIsUp = (_sentence->_sound && _sentence->_soundStarted && (!_sentence->_sound->IsPlaying() && !_sentence->_sound->IsPaused())) || (!_sentence->_sound && _sentence->_duration <= Game->_timer - _sentence->_startTime);
+ if (_tempSprite2 == NULL || _tempSprite2->_finished || (/*_tempSprite2->_looping &&*/ TimeIsUp)) {
+ if (TimeIsUp) {
+ _sentence->Finish();
+ _tempSprite2 = NULL;
+ _state = STATE_READY;
+ } else {
+ _tempSprite2 = GetTalkStance(_sentence->GetNextStance());
+ if (_tempSprite2) {
+ _tempSprite2->Reset();
+ _currentSprite = _tempSprite2;
+ }
+ ((CAdGame *)Game)->AddSentence(_sentence);
+ }
+ } else {
+ _currentSprite = _tempSprite2;
+ ((CAdGame *)Game)->AddSentence(_sentence);
+ }
+ }
+ break;
+ }
+ _ready = (_state == STATE_READY);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::Display(int X, int Y) {
+ int Width = 0;
+ if (_currentSprite) {
+ RECT rc;
+ _currentSprite->GetBoundingRect(&rc, 0, 0);
+ Width = rc.right - rc.left;
+ }
+
+ _posX = X + Width / 2;
+ _posY = Y;
+
+ HRESULT ret;
+ if (_currentSprite) ret = _currentSprite->Draw(X, Y, this, 100, 100, _alphaColor);
+ else ret = S_OK;
+
+ if (_displayAmount) {
+ int AmountX = X;
+ int AmountY = Y + _amountOffsetY;
+
+ if (_amountAlign == TAL_RIGHT) {
+ Width -= _amountOffsetX;
+ AmountX -= _amountOffsetX;
+ }
+ AmountX += _amountOffsetX;
+
+ CBFont *Font = _font ? _font : Game->_systemFont;
+ if (Font) {
+ if (_amountString) Font->DrawText((byte *)_amountString, AmountX, AmountY, Width, _amountAlign);
+ else {
+ char Str[256];
+ sprintf(Str, "%d", _amount);
+ Font->DrawText((byte *)Str, AmountX, AmountY, Width, _amountAlign);
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetHoverSprite
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetHoverSprite") == 0) {
+ Stack->CorrectParams(1);
+
+ bool SetCurrent = false;
+ if (_currentSprite && _currentSprite == _spriteHover) SetCurrent = true;
+
+ const char *Filename = Stack->Pop()->GetString();
+
+ delete _spriteHover;
+ _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 {
+ _spriteHover = spr;
+ if (SetCurrent) _currentSprite = _spriteHover;
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverSprite") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!_spriteHover || !_spriteHover->_filename) Stack->PushNULL();
+ else Stack->PushString(_spriteHover->_filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverSpriteObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverSpriteObject") == 0) {
+ Stack->CorrectParams(0);
+ if (!_spriteHover) Stack->PushNULL();
+ else Stack->PushNative(_spriteHover, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetNormalCursor
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetNormalCursor") == 0) {
+ Stack->CorrectParams(1);
+
+ const char *Filename = Stack->Pop()->GetString();
+
+ delete _cursorNormal;
+ _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 {
+ _cursorNormal = spr;
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetNormalCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetNormalCursor") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!_cursorNormal || !_cursorNormal->_filename) Stack->PushNULL();
+ else Stack->PushString(_cursorNormal->_filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetNormalCursorObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetNormalCursorObject") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!_cursorNormal) Stack->PushNULL();
+ else Stack->PushNative(_cursorNormal, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetHoverCursor
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetHoverCursor") == 0) {
+ Stack->CorrectParams(1);
+
+ const char *Filename = Stack->Pop()->GetString();
+
+ delete _cursorHover;
+ _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 {
+ _cursorHover = spr;
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverCursor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverCursor") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!_cursorHover || !_cursorHover->_filename) Stack->PushNULL();
+ else Stack->PushString(_cursorHover->_filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverCursorObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetHoverCursorObject") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!_cursorHover) Stack->PushNULL();
+ else Stack->PushNative(_cursorHover, true);
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdItem::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("item");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Name") == 0) {
+ _scValue->SetString(_name);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DisplayAmount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DisplayAmount") == 0) {
+ _scValue->SetBool(_displayAmount);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Amount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Amount") == 0) {
+ _scValue->SetInt(_amount);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetX") == 0) {
+ _scValue->SetInt(_amountOffsetX);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetY") == 0) {
+ _scValue->SetInt(_amountOffsetY);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountAlign") == 0) {
+ _scValue->SetInt(_amountAlign);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountString
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountString") == 0) {
+ if (!_amountString) _scValue->SetNULL();
+ else _scValue->SetString(_amountString);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorCombined
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CursorCombined") == 0) {
+ _scValue->SetBool(_cursorCombined);
+ return _scValue;
+ }
+
+ else return CAdTalkHolder::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::ScSetProperty(const char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DisplayAmount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DisplayAmount") == 0) {
+ _displayAmount = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Amount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Amount") == 0) {
+ _amount = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetX") == 0) {
+ _amountOffsetX = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountOffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountOffsetY") == 0) {
+ _amountOffsetY = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountAlign") == 0) {
+ _amountAlign = (TTextAlign)Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AmountString
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AmountString") == 0) {
+ if (Value->IsNULL()) {
+ delete[] _amountString;
+ _amountString = NULL;
+ } else {
+ CBUtils::SetString(&_amountString, Value->GetString());
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorCombined
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CursorCombined") == 0) {
+ _cursorCombined = Value->GetBool();
+ return S_OK;
+ }
+
+ else return CAdTalkHolder::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CAdItem::ScToString() {
+ return "[item]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdItem::Persist(CBPersistMgr *PersistMgr) {
+
+ CAdTalkHolder::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_cursorCombined));
+ PersistMgr->Transfer(TMEMBER(_cursorHover));
+ PersistMgr->Transfer(TMEMBER(_cursorNormal));
+ PersistMgr->Transfer(TMEMBER(_spriteHover));
+ PersistMgr->Transfer(TMEMBER(_inInventory));
+ PersistMgr->Transfer(TMEMBER(_displayAmount));
+ PersistMgr->Transfer(TMEMBER(_amount));
+ PersistMgr->Transfer(TMEMBER(_amountOffsetX));
+ PersistMgr->Transfer(TMEMBER(_amountOffsetY));
+ PersistMgr->Transfer(TMEMBER_INT(_amountAlign));
+ PersistMgr->Transfer(TMEMBER(_amountString));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdItem::GetExtendedFlag(const 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/Ad/AdItem.h b/engines/wintermute/Ad/AdItem.h
new file mode 100644
index 0000000000..0168ff7ca8
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADITEM_H
+#define WINTERMUTE_ADITEM_H
+
+
+#include "engines/wintermute/Ad/AdTalkHolder.h"
+
+namespace WinterMute {
+
+class CAdItem : public CAdTalkHolder {
+public:
+ bool _displayAmount;
+ int _amount;
+ int _amountOffsetX;
+ int _amountOffsetY;
+ TTextAlign _amountAlign;
+ char *_amountString;
+
+
+ HRESULT Update();
+ DECLARE_PERSISTENT(CAdItem, CAdTalkHolder)
+ HRESULT Display(int X, int Y);
+ bool GetExtendedFlag(const char *FlagName);
+ bool _inInventory;
+ bool _cursorCombined;
+ CBSprite *_spriteHover;
+ CBSprite *_cursorNormal;
+ CBSprite *_cursorHover;
+ CAdItem(CBGame *inGame);
+ virtual ~CAdItem();
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdLayer.cpp b/engines/wintermute/Ad/AdLayer.cpp
new file mode 100644
index 0000000000..b6e7a8527e
--- /dev/null
+++ b/engines/wintermute/Ad/AdLayer.cpp
@@ -0,0 +1,538 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/Ad/AdLayer.h"
+#include "engines/wintermute/Ad/AdSceneNode.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdLayer, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdLayer::CAdLayer(CBGame *inGame): CBObject(inGame) {
+ _main = false;
+ _width = _height = 0;
+ _active = true;
+ _closeUp = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdLayer::~CAdLayer() {
+ for (int i = 0; i < _nodes.GetSize(); i++)
+ delete _nodes[i];
+ _nodes.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdLayer::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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", &_main);
+ break;
+
+ case TOKEN_CLOSE_UP:
+ parser.ScanStr((char *)params, "%b", &_closeUp);
+ break;
+
+ case TOKEN_WIDTH:
+ parser.ScanStr((char *)params, "%d", &_width);
+ break;
+
+ case TOKEN_HEIGHT:
+ parser.ScanStr((char *)params, "%d", &_height);
+ break;
+
+ case TOKEN_ACTIVE:
+ parser.ScanStr((char *)params, "%b", &_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);
+ _nodes.Add(node);
+ }
+ }
+ break;
+
+ case TOKEN_ENTITY: {
+ CAdEntity *entity = new CAdEntity(Game);
+ CAdSceneNode *node = new CAdSceneNode(Game);
+ if (entity) entity->_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);
+ _nodes.Add(node);
+ }
+ }
+ break;
+
+ case TOKEN_EDITOR_SELECTED:
+ parser.ScanStr((char *)params, "%b", &_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, const char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // GetNode
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "GetNode") == 0) {
+ Stack->CorrectParams(1);
+ CScValue *val = Stack->Pop();
+ int node = -1;
+
+ if (val->_type == VAL_INT) node = val->GetInt();
+ else { // get by name
+ for (int i = 0; i < _nodes.GetSize(); i++) {
+ if ((_nodes[i]->_type == OBJECT_ENTITY && scumm_stricmp(_nodes[i]->_entity->_name, val->GetString()) == 0) ||
+ (_nodes[i]->_type == OBJECT_REGION && scumm_stricmp(_nodes[i]->_region->_name, val->GetString()) == 0)) {
+ node = i;
+ break;
+ }
+ }
+ }
+
+ if (node < 0 || node >= _nodes.GetSize()) Stack->PushNULL();
+ else {
+ switch (_nodes[node]->_type) {
+ case OBJECT_ENTITY:
+ Stack->PushNative(_nodes[node]->_entity, true);
+ break;
+ case OBJECT_REGION:
+ Stack->PushNative(_nodes[node]->_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);
+ }
+ _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 <= _nodes.GetSize() - 1) _nodes.InsertAt(Index, Node);
+ else _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 < _nodes.GetSize(); i++) {
+ if (_nodes[i]->_region == Temp || _nodes[i]->_entity == Temp) {
+ ToDelete = _nodes[i];
+ break;
+ }
+ }
+ } else {
+ int Index = Val->GetInt();
+ if (Index >= 0 && Index < _nodes.GetSize()) {
+ ToDelete = _nodes[Index];
+ }
+ }
+ if (ToDelete == NULL) {
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ for (int i = 0; i < _nodes.GetSize(); i++) {
+ if (_nodes[i] == ToDelete) {
+ delete _nodes[i];
+ _nodes[i] = NULL;
+ _nodes.RemoveAt(i);
+ break;
+ }
+ }
+ Stack->PushBool(true);
+ return S_OK;
+ }
+
+ else return CBObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdLayer::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("layer");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumNodes (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumNodes") == 0) {
+ _scValue->SetInt(_nodes.GetSize());
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Width
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ _scValue->SetInt(_width);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Height
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ _scValue->SetInt(_height);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Main (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Main") == 0) {
+ _scValue->SetBool(_main);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CloseUp
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CloseUp") == 0) {
+ _scValue->SetBool(_closeUp);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ _scValue->SetBool(_active);
+ return _scValue;
+ }
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::ScSetProperty(const char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CloseUp
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "CloseUp") == 0) {
+ _closeUp = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Width
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ _width = Value->GetInt();
+ if (_width < 0) _width = 0;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Height
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ _height = Value->GetInt();
+ if (_height < 0) _height = 0;
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ bool b = Value->GetBool();
+ if (b == false && _main) {
+ Game->LOG(0, "Warning: cannot deactivate scene's main layer");
+ } else _active = b;
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CAdLayer::ScToString() {
+ return "[layer]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdLayer::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "LAYER {\n");
+ Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", _name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+ Buffer->PutTextIndent(Indent + 2, "MAIN=%s\n", _main ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "WIDTH=%d\n", _width);
+ Buffer->PutTextIndent(Indent + 2, "HEIGHT=%d\n", _height);
+ Buffer->PutTextIndent(Indent + 2, "ACTIVE=%s\n", _active ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", _editorSelected ? "TRUE" : "FALSE");
+ if (_closeUp)
+ Buffer->PutTextIndent(Indent + 2, "CLOSE_UP=%s\n", _closeUp ? "TRUE" : "FALSE");
+
+ int i;
+
+ for (i = 0; i < _scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ if (_scProp) _scProp->SaveAsText(Buffer, Indent + 2);
+
+ for (i = 0; i < _nodes.GetSize(); i++) {
+ switch (_nodes[i]->_type) {
+ case OBJECT_ENTITY:
+ _nodes[i]->_entity->SaveAsText(Buffer, Indent + 2);
+ break;
+ case OBJECT_REGION:
+ _nodes[i]->_region->SaveAsText(Buffer, Indent + 2);
+ break;
+ default:
+ error("CAdLayer::SaveAsText - Unhandled enum");
+ 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(_active));
+ PersistMgr->Transfer(TMEMBER(_closeUp));
+ PersistMgr->Transfer(TMEMBER(_height));
+ PersistMgr->Transfer(TMEMBER(_main));
+ _nodes.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_width));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdLayer.h b/engines/wintermute/Ad/AdLayer.h
new file mode 100644
index 0000000000..1c0e3fa946
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADLAYER_H
+#define WINTERMUTE_ADLAYER_H
+
+namespace WinterMute {
+class CAdSceneNode;
+class CAdLayer : public CBObject {
+public:
+ bool _closeUp;
+ DECLARE_PERSISTENT(CAdLayer, CBObject)
+ bool _active;
+ int _height;
+ int _width;
+ bool _main;
+ CAdLayer(CBGame *inGame);
+ virtual ~CAdLayer();
+ CBArray<CAdSceneNode *, CAdSceneNode *> _nodes;
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdNodeState.cpp b/engines/wintermute/Ad/AdNodeState.cpp
new file mode 100644
index 0000000000..05ff99f7e0
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/Ad/AdNodeState.h"
+#include "engines/wintermute/Ad/AdEntity.h"
+#include "engines/wintermute/BStringTable.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/utils.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdNodeState, false)
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdNodeState::CAdNodeState(CBGame *inGame): CBBase(inGame) {
+ _name = NULL;
+ _active = false;
+ for (int i = 0; i < 7; i++) _caption[i] = NULL;
+ _alphaColor = 0;
+ _filename = NULL;
+ _cursor = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdNodeState::~CAdNodeState() {
+ delete[] _name;
+ delete[] _filename;
+ delete[] _cursor;
+ _name = NULL;
+ _filename = NULL;
+ _cursor = NULL;
+ for (int i = 0; i < 7; i++) {
+ delete[] _caption[i];
+ _caption[i] = NULL;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetName(const char *Name) {
+ delete[] _name;
+ _name = NULL;
+ CBUtils::SetString(&_name, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetFilename(const char *Filename) {
+ delete[] _filename;
+ _filename = NULL;
+ CBUtils::SetString(&_filename, Filename);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetCursor(const char *Filename) {
+ delete[] _cursor;
+ _cursor = NULL;
+ CBUtils::SetString(&_cursor, Filename);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdNodeState::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(Game));
+
+ PersistMgr->Transfer(TMEMBER(_active));
+ PersistMgr->Transfer(TMEMBER(_name));
+ PersistMgr->Transfer(TMEMBER(_filename));
+ PersistMgr->Transfer(TMEMBER(_cursor));
+ PersistMgr->Transfer(TMEMBER(_alphaColor));
+ for (int i = 0; i < 7; i++) PersistMgr->Transfer(TMEMBER(_caption[i]));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdNodeState::SetCaption(const char *Caption, int Case) {
+ if (Case == 0) Case = 1;
+ if (Case < 1 || Case > 7) return;
+
+ delete[] _caption[Case - 1];
+ _caption[Case - 1] = new char[strlen(Caption) + 1];
+ if (_caption[Case - 1]) {
+ strcpy(_caption[Case - 1], Caption);
+ Game->_stringTable->Expand(&_caption[Case - 1]);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdNodeState::GetCaption(int Case) {
+ if (Case == 0) Case = 1;
+ if (Case < 1 || Case > 7 || _caption[Case - 1] == NULL) return "";
+ else return _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->_caption[i]) SetCaption(Entity->_caption[i], i);
+ }
+ if (!Entity->_region && Entity->_sprite && Entity->_sprite->_filename) {
+ if (IncludingSprites) SetFilename(Entity->_sprite->_filename);
+ else SetFilename("");
+ }
+ if (Entity->_cursor && Entity->_cursor->_filename) SetCursor(Entity->_cursor->_filename);
+ _alphaColor = Entity->_alphaColor;
+ _active = Entity->_active;
+ } else {
+ for (int i = 0; i < 7; i++) {
+ if (_caption[i]) Entity->SetCaption(_caption[i], i);
+ }
+ if (_filename && !Entity->_region && IncludingSprites && strcmp(_filename, "") != 0) {
+ if (!Entity->_sprite || !Entity->_sprite->_filename || scumm_stricmp(Entity->_sprite->_filename, _filename) != 0)
+ Entity->SetSprite(_filename);
+ }
+ if (_cursor) {
+ if (!Entity->_cursor || !Entity->_cursor->_filename || scumm_stricmp(Entity->_cursor->_filename, _cursor) != 0)
+ Entity->SetCursor(_cursor);
+ }
+
+ Entity->_active = _active;
+ Entity->_alphaColor = _alphaColor;
+ }
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdNodeState.h b/engines/wintermute/Ad/AdNodeState.h
new file mode 100644
index 0000000000..16445376ca
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADNODESTATE_H
+#define WINTERMUTE_ADNODESTATE_H
+
+namespace WinterMute {
+
+class CAdEntity;
+
+class CAdNodeState : public CBBase {
+public:
+ HRESULT TransferEntity(CAdEntity *Entity, bool IncludingSprites, bool Saving);
+ void SetName(const char *Name);
+ void SetFilename(const char *Filename);
+ void SetCursor(const char *Filename);
+ DECLARE_PERSISTENT(CAdNodeState, CBBase)
+ CAdNodeState(CBGame *inGame);
+ virtual ~CAdNodeState();
+ char *_name;
+ bool _active;
+ char *_caption[7];
+ void SetCaption(const char *Caption, int Case);
+ char *GetCaption(int Case);
+ uint32 _alphaColor;
+ char *_filename;
+ char *_cursor;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdObject.cpp b/engines/wintermute/Ad/AdObject.cpp
new file mode 100644
index 0000000000..34903a8ccf
--- /dev/null
+++ b/engines/wintermute/Ad/AdObject.cpp
@@ -0,0 +1,1203 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdItem.h"
+#include "engines/wintermute/Ad/AdObject.h"
+#include "engines/wintermute/Ad/AdInventory.h"
+#include "engines/wintermute/Ad/AdLayer.h"
+#include "engines/wintermute/Ad/AdScene.h"
+#include "engines/wintermute/Ad/AdSceneNode.h"
+#include "engines/wintermute/Ad/AdSentence.h"
+#include "engines/wintermute/Ad/AdWaypointGroup.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BFrame.h"
+#include "engines/wintermute/BSound.h"
+#include "engines/wintermute/BSurfaceStorage.h"
+#include "engines/wintermute/BSubFrame.h"
+#include "engines/wintermute/BFont.h"
+#include "engines/wintermute/BFontStorage.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BStringTable.h"
+#include "engines/wintermute/scriptables/ScEngine.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "common/str.h"
+#include "common/util.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdObject, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdObject::CAdObject(CBGame *inGame): CBObject(inGame) {
+ _type = OBJECT_NONE;
+ _state = _nextState = STATE_NONE;
+
+ _active = true;
+ _drawn = false;
+
+ _currentSprite = NULL;
+ _animSprite = NULL;
+ _tempSprite2 = NULL;
+
+ _font = NULL;
+
+ _sentence = NULL;
+
+ _forcedTalkAnimName = NULL;
+ _forcedTalkAnimUsed = false;
+
+ _blockRegion = NULL;
+ _wptGroup = NULL;
+
+ _currentBlockRegion = NULL;
+ _currentWptGroup = NULL;
+
+ _ignoreItems = false;
+ _sceneIndependent = false;
+
+ _stickRegion = NULL;
+
+ _subtitlesModRelative = true;
+ _subtitlesModX = 0;
+ _subtitlesModY = 0;
+ _subtitlesWidth = 0;
+ _subtitlesModXCenter = true;
+
+ _inventory = NULL;
+
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) _currentRegions[i] = NULL;
+
+ _partEmitter = NULL;
+ _partFollowParent = false;
+ _partOffsetX = _partOffsetY = 0;
+
+ _registerAlias = this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdObject::~CAdObject() {
+ _currentSprite = NULL; // reference only, don't delete
+ delete _animSprite;
+ _animSprite = NULL;
+ delete _sentence;
+ _sentence = NULL;
+ delete[] _forcedTalkAnimName;
+ _forcedTalkAnimName = NULL;
+
+ delete _blockRegion;
+ _blockRegion = NULL;
+ delete _wptGroup;
+ _wptGroup = NULL;
+
+ delete _currentBlockRegion;
+ _currentBlockRegion = NULL;
+ delete _currentWptGroup;
+ _currentWptGroup = NULL;
+
+ _tempSprite2 = NULL; // reference only
+ _stickRegion = NULL;
+
+ if (_font) Game->_fontStorage->RemoveFont(_font);
+
+ if (_inventory) {
+ ((CAdGame *)Game)->UnregisterInventory(_inventory);
+ _inventory = NULL;
+ }
+
+ if (_partEmitter)
+ Game->UnregisterObject(_partEmitter);
+
+
+ for (int i = 0; i < _attachmentsPre.GetSize(); i++) {
+ Game->UnregisterObject(_attachmentsPre[i]);
+ }
+ _attachmentsPre.RemoveAll();
+
+ for (int i = 0; i < _attachmentsPost.GetSize(); i++) {
+ Game->UnregisterObject(_attachmentsPost[i]);
+ }
+ _attachmentsPost.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::PlayAnim(const char *Filename) {
+ delete _animSprite;
+ _animSprite = NULL;
+ _animSprite = new CBSprite(Game, this);
+ if (!_animSprite) {
+ Game->LOG(0, "CAdObject::PlayAnim: error creating temp sprite (object:\"%s\" sprite:\"%s\")", _name, Filename);
+ return E_FAIL;
+ }
+ HRESULT res = _animSprite->LoadFile(Filename);
+ if (FAILED(res)) {
+ Game->LOG(res, "CAdObject::PlayAnim: error loading temp sprite (object:\"%s\" sprite:\"%s\")", _name, Filename);
+ delete _animSprite;
+ _animSprite = NULL;
+ return res;
+ }
+ _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, const 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(_state == STATE_TALKING);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // StopTalk / StopTalking
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "StopTalk") == 0 || strcmp(Name, "StopTalking") == 0) {
+ Stack->CorrectParams(0);
+ if (_sentence) _sentence->Finish();
+ if (_state == STATE_TALKING) {
+ _state = _nextState;
+ _nextState = STATE_READY;
+ Stack->PushBool(true);
+ } else Stack->PushBool(false);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ForceTalkAnim
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ForceTalkAnim") == 0) {
+ Stack->CorrectParams(1);
+ const char *AnimName = Stack->Pop()->GetString();
+ delete[] _forcedTalkAnimName;
+ _forcedTalkAnimName = new char[strlen(AnimName) + 1];
+ strcpy(_forcedTalkAnimName, AnimName);
+ _forcedTalkAnimUsed = false;
+ Stack->PushBool(true);
+ return S_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Talk / TalkAsync
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Talk") == 0 || strcmp(Name, "TalkAsync") == 0) {
+ Stack->CorrectParams(5);
+
+ const char *Text = Stack->Pop()->GetString();
+ CScValue *SoundVal = Stack->Pop();
+ int Duration = Stack->Pop()->GetInt();
+ CScValue *ValStances = Stack->Pop();
+
+ const char *Stances = ValStances->IsNULL() ? NULL : ValStances->GetString();
+
+ int Align;
+ CScValue *val = Stack->Pop();
+ if (val->IsNULL()) Align = TAL_CENTER;
+ else Align = val->GetInt();
+
+ Align = MIN(MAX(0, Align), NUM_TEXT_ALIGN - 1);
+
+ const 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)->_scene->_mainLayer;
+ bool RegFound = false;
+
+ int i;
+ CScValue *Val = Stack->Pop();
+ if (Val->IsNULL() || !Main) {
+ _stickRegion = NULL;
+ RegFound = true;
+ } else if (Val->IsString()) {
+ const char *RegionName = Val->GetString();
+ for (i = 0; i < Main->_nodes.GetSize(); i++) {
+ if (Main->_nodes[i]->_type == OBJECT_REGION && Main->_nodes[i]->_region->_name && scumm_stricmp(Main->_nodes[i]->_region->_name, RegionName) == 0) {
+ _stickRegion = Main->_nodes[i]->_region;
+ RegFound = true;
+ break;
+ }
+ }
+ } else if (Val->IsNative()) {
+ CBScriptable *Obj = Val->GetNative();
+
+ for (i = 0; i < Main->_nodes.GetSize(); i++) {
+ if (Main->_nodes[i]->_type == OBJECT_REGION && Main->_nodes[i]->_region == Obj) {
+ _stickRegion = Main->_nodes[i]->_region;
+ RegFound = true;
+ break;
+ }
+ }
+
+ }
+
+ if (!RegFound) _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 (_font && _font->_filename) Stack->PushString(_font->_filename);
+ else Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TakeItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "TakeItem") == 0) {
+ Stack->CorrectParams(2);
+
+ if (!_inventory) {
+ _inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(_inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (!val->IsNULL()) {
+ const char *ItemName = val->GetString();
+ val = Stack->Pop();
+ const char *InsertAfter = val->IsNULL() ? NULL : val->GetString();
+ if (FAILED(_inventory->InsertItem(ItemName, InsertAfter))) Script->RuntimeError("Cannot add item '%s' to inventory", ItemName);
+ else {
+ // hide associated entities
+ ((CAdGame *)Game)->_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 (!_inventory) {
+ _inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(_inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (!val->IsNULL()) {
+ if (FAILED(_inventory->RemoveItem(val->GetString()))) Script->RuntimeError("Cannot remove item '%s' from inventory", val->GetString());
+ else {
+ // show associated entities
+ ((CAdGame *)Game)->_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 (!_inventory) {
+ _inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(_inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (val->_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() >= _inventory->_takenItems.GetSize())
+ Stack->PushNULL();
+ else
+ Stack->PushNative(_inventory->_takenItems[val->GetInt()], true);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HasItem
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "HasItem") == 0) {
+ Stack->CorrectParams(1);
+
+ if (!_inventory) {
+ _inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(_inventory);
+ }
+
+ CScValue *val = Stack->Pop();
+ if (!val->IsNULL()) {
+ for (int i = 0; i < _inventory->_takenItems.GetSize(); i++) {
+ if (val->GetNative() == _inventory->_takenItems[i]) {
+ Stack->PushBool(true);
+ return S_OK;
+ } else if (scumm_stricmp(val->GetString(), _inventory->_takenItems[i]->_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(_partEmitter, true);
+ else Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteParticleEmitter
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "DeleteParticleEmitter") == 0) {
+ Stack->CorrectParams(0);
+ if (_partEmitter) {
+ Game->UnregisterObject(_partEmitter);
+ _partEmitter = NULL;
+ }
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddAttachment
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddAttachment") == 0) {
+ Stack->CorrectParams(4);
+ const 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))) {
+ delete Ent;
+ Ent = NULL;
+ Script->RuntimeError("AddAttachment() failed loading entity '%s'", Filename);
+ Stack->PushBool(false);
+ } else {
+ Game->RegisterObject(Ent);
+
+ Ent->_posX = OffsetX;
+ Ent->_posY = OffsetY;
+ Ent->_active = true;
+
+ if (PreDisplay) _attachmentsPre.Add(Ent);
+ else _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 < _attachmentsPre.GetSize(); i++) {
+ if (_attachmentsPre[i] == Obj) {
+ Found = true;
+ Game->UnregisterObject(_attachmentsPre[i]);
+ _attachmentsPre.RemoveAt(i);
+ i--;
+ }
+ }
+ for (int i = 0; i < _attachmentsPost.GetSize(); i++) {
+ if (_attachmentsPost[i] == Obj) {
+ Found = true;
+ Game->UnregisterObject(_attachmentsPost[i]);
+ _attachmentsPost.RemoveAt(i);
+ i--;
+ }
+ }
+ } else {
+ const char *Name = Val->GetString();
+ for (int i = 0; i < _attachmentsPre.GetSize(); i++) {
+ if (_attachmentsPre[i]->_name && scumm_stricmp(_attachmentsPre[i]->_name, Name) == 0) {
+ Found = true;
+ Game->UnregisterObject(_attachmentsPre[i]);
+ _attachmentsPre.RemoveAt(i);
+ i--;
+ }
+ }
+ for (int i = 0; i < _attachmentsPost.GetSize(); i++) {
+ if (_attachmentsPost[i]->_name && scumm_stricmp(_attachmentsPost[i]->_name, Name) == 0) {
+ Found = true;
+ Game->UnregisterObject(_attachmentsPost[i]);
+ _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 < _attachmentsPre.GetSize(); i++) {
+ if (CurrIndex == Index) Ret = _attachmentsPre[i];
+ CurrIndex++;
+ }
+ for (int i = 0; i < _attachmentsPost.GetSize(); i++) {
+ if (CurrIndex == Index) Ret = _attachmentsPost[i];
+ CurrIndex++;
+ }
+ } else {
+ const char *Name = Val->GetString();
+ for (int i = 0; i < _attachmentsPre.GetSize(); i++) {
+ if (_attachmentsPre[i]->_name && scumm_stricmp(_attachmentsPre[i]->_name, Name) == 0) {
+ Ret = _attachmentsPre[i];
+ break;
+ }
+ }
+ if (!Ret) {
+ for (int i = 0; i < _attachmentsPost.GetSize(); i++) {
+ if (_attachmentsPost[i]->_name && scumm_stricmp(_attachmentsPost[i]->_name, Name) == 0) {
+ Ret = _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(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("object");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ _scValue->SetBool(_active);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IgnoreItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IgnoreItems") == 0) {
+ _scValue->SetBool(_ignoreItems);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SceneIndependent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SceneIndependent") == 0) {
+ _scValue->SetBool(_sceneIndependent);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesWidth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesWidth") == 0) {
+ _scValue->SetInt(_subtitlesWidth);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosRelative
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosRelative") == 0) {
+ _scValue->SetBool(_subtitlesModRelative);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosX") == 0) {
+ _scValue->SetInt(_subtitlesModX);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosY") == 0) {
+ _scValue->SetInt(_subtitlesModY);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosXCenter
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosXCenter") == 0) {
+ _scValue->SetBool(_subtitlesModXCenter);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumItems (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumItems") == 0) {
+ _scValue->SetInt(GetInventory()->_takenItems.GetSize());
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ParticleEmitter (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ParticleEmitter") == 0) {
+ if (_partEmitter) _scValue->SetNative(_partEmitter, true);
+ else _scValue->SetNULL();
+
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumAttachments (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumAttachments") == 0) {
+ _scValue->SetInt(_attachmentsPre.GetSize() + _attachmentsPost.GetSize());
+ return _scValue;
+ }
+
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::ScSetProperty(const char *Name, CScValue *Value) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Active") == 0) {
+ _active = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // IgnoreItems
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "IgnoreItems") == 0) {
+ _ignoreItems = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SceneIndependent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SceneIndependent") == 0) {
+ _sceneIndependent = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesWidth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesWidth") == 0) {
+ _subtitlesWidth = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosRelative
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosRelative") == 0) {
+ _subtitlesModRelative = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosX") == 0) {
+ _subtitlesModX = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosY") == 0) {
+ _subtitlesModY = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SubtitlesPosXCenter
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SubtitlesPosXCenter") == 0) {
+ _subtitlesModXCenter = Value->GetBool();
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CAdObject::ScToString() {
+ return "[ad object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::SetFont(const char *Filename) {
+ if (_font) Game->_fontStorage->RemoveFont(_font);
+ if (Filename) {
+ _font = Game->_fontStorage->AddFont(Filename);
+ return _font == NULL ? E_FAIL : S_OK;
+ } else {
+ _font = NULL;
+ return S_OK;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdObject::GetHeight() {
+ if (!_currentSprite) return 0;
+ else {
+ CBFrame *frame = _currentSprite->_frames[_currentSprite->_currentFrame];
+ int ret = 0;
+ for (int i = 0; i < frame->_subframes.GetSize(); i++) {
+ ret = MAX(ret, frame->_subframes[i]->_hotspotY);
+ }
+
+ if (_zoomable) {
+ float zoom = ((CAdGame *)Game)->_scene->GetZoomAt(_posX, _posY);
+ ret = ret * zoom / 100;
+ }
+ return ret;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdObject::Talk(const char *Text, const char *Sound, uint32 Duration, const char *Stances, TTextAlign Align) {
+ if (!_sentence) _sentence = new CAdSentence(Game);
+ if (!_sentence) return;
+
+ if (_forcedTalkAnimName && _forcedTalkAnimUsed) {
+ delete[] _forcedTalkAnimName;
+ _forcedTalkAnimName = NULL;
+ _forcedTalkAnimUsed = false;
+ }
+
+ delete (_sentence->_sound);
+ _sentence->_sound = NULL;
+
+ _sentence->SetText(Text);
+ Game->_stringTable->Expand(&_sentence->_text);
+ _sentence->SetStances(Stances);
+ _sentence->_duration = Duration;
+ _sentence->_align = Align;
+ _sentence->_startTime = Game->_timer;
+ _sentence->_currentStance = -1;
+ _sentence->_font = _font == NULL ? Game->_systemFont : _font;
+ _sentence->_freezable = _freezable;
+
+ // try to locate speech file automatically
+ bool DeleteSound = false;
+ if (!Sound) {
+ char *Key = Game->_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))) {
+ _sentence->SetSound(snd);
+ if (_sentence->_duration <= 0) {
+ uint32 Length = snd->GetLength();
+ if (Length != 0) _sentence->_duration = Length;
+ }
+ } else delete snd;
+ }
+
+ // set duration by text length
+ if (_sentence->_duration <= 0) {// TODO: Avoid longs.
+ _sentence->_duration = MAX((size_t)1000, Game->_subtitlesSpeed * strlen(_sentence->_text));
+ }
+
+
+ int x, y, width, height;
+
+ x = _posX;
+ y = _posY;
+
+ if (!_sceneIndependent && _subtitlesModRelative) {
+ x -= ((CAdGame *)Game)->_scene->GetOffsetLeft();
+ y -= ((CAdGame *)Game)->_scene->GetOffsetTop();
+ }
+
+
+ if (_subtitlesWidth > 0) width = _subtitlesWidth;
+ else {
+ if ((x < Game->_renderer->_width / 4 || x > Game->_renderer->_width * 0.75) && !Game->_touchInterface) {
+ width = MAX(Game->_renderer->_width / 4, MIN(x * 2, (Game->_renderer->_width - x) * 2));
+ } else width = Game->_renderer->_width / 2;
+ }
+
+ height = _sentence->_font->GetTextHeight((byte *)_sentence->_text, width);
+
+ y = y - height - GetHeight() - 5;
+ if (_subtitlesModRelative) {
+ x += _subtitlesModX;
+ y += _subtitlesModY;
+ } else {
+ x = _subtitlesModX;
+ y = _subtitlesModY;
+ }
+ if (_subtitlesModXCenter)
+ x = x - width / 2;
+
+
+ x = MIN(MAX(0, x), Game->_renderer->_width - width);
+ y = MIN(MAX(0, y), Game->_renderer->_height - height);
+
+ _sentence->_width = width;
+
+
+ _sentence->_pos.x = x;
+ _sentence->_pos.y = y;
+
+
+ if (_subtitlesModRelative) {
+ _sentence->_pos.x += ((CAdGame *)Game)->_scene->GetOffsetLeft();
+ _sentence->_pos.y += ((CAdGame *)Game)->_scene->GetOffsetTop();
+ }
+
+ _sentence->_fixedPos = !_subtitlesModRelative;
+
+
+ _sentence->SetupTalkFile(Sound);
+
+ _state = STATE_TALKING;
+
+ if (DeleteSound) delete [] Sound;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::Reset() {
+ if (_state == STATE_PLAYING_ANIM && _animSprite != NULL) {
+ delete _animSprite;
+ _animSprite = NULL;
+ } else if (_state == STATE_TALKING && _sentence) {
+ _sentence->Finish();
+ }
+
+ _state = _nextState = STATE_READY;
+
+ Game->_scEngine->ResetObject(this);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_active));
+ PersistMgr->Transfer(TMEMBER(_blockRegion));
+ PersistMgr->Transfer(TMEMBER(_currentBlockRegion));
+ PersistMgr->Transfer(TMEMBER(_currentWptGroup));
+ PersistMgr->Transfer(TMEMBER(_currentSprite));
+ PersistMgr->Transfer(TMEMBER(_drawn));
+ PersistMgr->Transfer(TMEMBER(_font));
+ PersistMgr->Transfer(TMEMBER(_ignoreItems));
+ PersistMgr->Transfer(TMEMBER_INT(_nextState));
+ PersistMgr->Transfer(TMEMBER(_sentence));
+ PersistMgr->Transfer(TMEMBER_INT(_state));
+ PersistMgr->Transfer(TMEMBER(_animSprite));
+ PersistMgr->Transfer(TMEMBER(_sceneIndependent));
+ PersistMgr->Transfer(TMEMBER(_forcedTalkAnimName));
+ PersistMgr->Transfer(TMEMBER(_forcedTalkAnimUsed));
+ PersistMgr->Transfer(TMEMBER(_tempSprite2));
+ PersistMgr->Transfer(TMEMBER_INT(_type));
+ PersistMgr->Transfer(TMEMBER(_wptGroup));
+ PersistMgr->Transfer(TMEMBER(_stickRegion));
+ PersistMgr->Transfer(TMEMBER(_subtitlesModRelative));
+ PersistMgr->Transfer(TMEMBER(_subtitlesModX));
+ PersistMgr->Transfer(TMEMBER(_subtitlesModY));
+ PersistMgr->Transfer(TMEMBER(_subtitlesModXCenter));
+ PersistMgr->Transfer(TMEMBER(_subtitlesWidth));
+ PersistMgr->Transfer(TMEMBER(_inventory));
+ PersistMgr->Transfer(TMEMBER(_partEmitter));
+
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) PersistMgr->Transfer(TMEMBER(_currentRegions[i]));
+
+ _attachmentsPre.Persist(PersistMgr);
+ _attachmentsPost.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_registerAlias));
+
+ PersistMgr->Transfer(TMEMBER(_partFollowParent));
+ PersistMgr->Transfer(TMEMBER(_partOffsetX));
+ PersistMgr->Transfer(TMEMBER(_partOffsetY));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdateSounds() {
+ if (_sentence && _sentence->_sound)
+ UpdateOneSound(_sentence->_sound);
+
+ return CBObject::UpdateSounds();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::ResetSoundPan() {
+ if (_sentence && _sentence->_sound) {
+ _sentence->_sound->SetPan(0.0f);
+ }
+ return CBObject::ResetSoundPan();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdObject::GetExtendedFlag(const 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 (_blockRegion) _blockRegion->SaveAsText(Buffer, Indent + 2, "BLOCKED_REGION");
+ if (_wptGroup) _wptGroup->SaveAsText(Buffer, Indent + 2);
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdateBlockRegion() {
+ CAdGame *AdGame = (CAdGame *)Game;
+ if (AdGame->_scene) {
+ if (_blockRegion && _currentBlockRegion)
+ _currentBlockRegion->Mimic(_blockRegion, _zoomable ? AdGame->_scene->GetScaleAt(_posY) : 100.0f, _posX, _posY);
+
+ if (_wptGroup && _currentWptGroup)
+ _currentWptGroup->Mimic(_wptGroup, _zoomable ? AdGame->_scene->GetScaleAt(_posY) : 100.0f, _posX, _posY);
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CAdInventory *CAdObject::GetInventory() {
+ if (!_inventory) {
+ _inventory = new CAdInventory(Game);
+ ((CAdGame *)Game)->RegisterInventory(_inventory);
+ }
+ return _inventory;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::AfterMove() {
+ CAdRegion *NewRegions[MAX_NUM_REGIONS];
+
+ ((CAdGame *)Game)->_scene->GetRegionsAt(_posX, _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 (_currentRegions[j] == NewRegions[i]) {
+ _currentRegions[j] = NULL;
+ RegFound = true;
+ break;
+ }
+ }
+ if (!RegFound) NewRegions[i]->ApplyEvent("ActorEntry");
+ }
+
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) {
+ if (_currentRegions[i] && Game->ValidObject(_currentRegions[i])) {
+ _currentRegions[i]->ApplyEvent("ActorLeave");
+ }
+ _currentRegions[i] = NewRegions[i];
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::InvalidateCurrRegions() {
+ for (int i = 0; i < MAX_NUM_REGIONS; i++) _currentRegions[i] = NULL;
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::GetScale(float *ScaleX, float *ScaleY) {
+ if (_zoomable) {
+ if (_scaleX >= 0 || _scaleY >= 0) {
+ *ScaleX = _scaleX < 0 ? 100 : _scaleX;
+ *ScaleY = _scaleY < 0 ? 100 : _scaleY;
+ } else if (_scale >= 0) *ScaleX = *ScaleY = _scale;
+ else *ScaleX = *ScaleY = ((CAdGame *)Game)->_scene->GetZoomAt(_posX, _posY) + _relativeScale;
+ } else {
+ *ScaleX = *ScaleY = 100;
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdateSpriteAttachments() {
+ for (int i = 0; i < _attachmentsPre.GetSize(); i++) {
+ _attachmentsPre[i]->Update();
+ }
+ for (int i = 0; i < _attachmentsPost.GetSize(); i++) {
+ _attachmentsPost[i]->Update();
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::DisplaySpriteAttachments(bool PreDisplay) {
+ if (PreDisplay) {
+ for (int i = 0; i < _attachmentsPre.GetSize(); i++) {
+ DisplaySpriteAttachment(_attachmentsPre[i]);
+ }
+ } else {
+ for (int i = 0; i < _attachmentsPost.GetSize(); i++) {
+ DisplaySpriteAttachment(_attachmentsPost[i]);
+ }
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::DisplaySpriteAttachment(CAdObject *Attachment) {
+ if (!Attachment->_active) return S_OK;
+
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+ int OrigX = Attachment->_posX;
+ int OrigY = Attachment->_posY;
+
+ // inherit position from owner
+ Attachment->_posX = this->_posX + Attachment->_posX * ScaleX / 100.0f;
+ Attachment->_posY = this->_posY + Attachment->_posY * ScaleY / 100.0f;
+
+ // inherit other props
+ Attachment->_alphaColor = this->_alphaColor;
+ Attachment->_blendMode = this->_blendMode;
+
+ Attachment->_scale = this->_scale;
+ Attachment->_relativeScale = this->_relativeScale;
+ Attachment->_scaleX = this->_scaleX;
+ Attachment->_scaleY = this->_scaleY;
+
+ Attachment->_rotate = this->_rotate;
+ Attachment->_relativeRotate = this->_relativeRotate;
+ Attachment->_rotateValid = this->_rotateValid;
+
+ Attachment->_registerAlias = this;
+ Attachment->_registrable = this->_registrable;
+
+ HRESULT ret = Attachment->Display();
+
+ Attachment->_posX = OrigX;
+ Attachment->_posY = OrigY;
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CPartEmitter *CAdObject::CreateParticleEmitter(bool FollowParent, int OffsetX, int OffsetY) {
+ _partFollowParent = FollowParent;
+ _partOffsetX = OffsetX;
+ _partOffsetY = OffsetY;
+
+ if (!_partEmitter) {
+ _partEmitter = new CPartEmitter(Game, this);
+ if (_partEmitter) {
+ Game->RegisterObject(_partEmitter);
+ }
+ }
+ UpdatePartEmitter();
+ return _partEmitter;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdObject::UpdatePartEmitter() {
+ if (!_partEmitter) return E_FAIL;
+
+ if (_partFollowParent) {
+ float ScaleX, ScaleY;
+ GetScale(&ScaleX, &ScaleY);
+
+ _partEmitter->_posX = _posX + (ScaleX / 100.0f) * _partOffsetX;
+ _partEmitter->_posY = _posY + (ScaleY / 100.0f) * _partOffsetY;
+ }
+ return _partEmitter->Update();
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdObject.h b/engines/wintermute/Ad/AdObject.h
new file mode 100644
index 0000000000..5f47c0d394
--- /dev/null
+++ b/engines/wintermute/Ad/AdObject.h
@@ -0,0 +1,123 @@
+/* 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 WINTERMUTE_ADOBJECT_H
+#define WINTERMUTE_ADOBJECT_H
+
+#include "engines/wintermute/Ad/AdTypes.h"
+#include "engines/wintermute/PartEmitter.h"
+
+namespace WinterMute {
+
+class CAdWaypointGroup;
+class CAdRegion;
+class CAdSentence;
+class CBFont;
+class CBRegion;
+class CAdInventory;
+
+#define MAX_NUM_REGIONS 10
+
+class CAdObject : public CBObject {
+public:
+ CPartEmitter *_partEmitter;
+ virtual CPartEmitter *CreateParticleEmitter(bool FollowParent = false, int OffsetX = 0, int OffsetY = 0);
+ virtual HRESULT UpdatePartEmitter();
+ bool _partFollowParent;
+ int _partOffsetX;
+ int _partOffsetY;
+
+ HRESULT InvalidateCurrRegions();
+ bool _subtitlesModRelative;
+ bool _subtitlesModXCenter;
+ int _subtitlesModX;
+ int _subtitlesModY;
+ int _subtitlesWidth;
+ CAdRegion *_stickRegion;
+ bool _sceneIndependent;
+ bool _ignoreItems;
+ HRESULT UpdateBlockRegion();
+ bool _forcedTalkAnimUsed;
+ char *_forcedTalkAnimName;
+ virtual bool GetExtendedFlag(const char *FlagName);
+ virtual HRESULT ResetSoundPan();
+ virtual HRESULT UpdateSounds();
+ HRESULT Reset();
+ DECLARE_PERSISTENT(CAdObject, CBObject)
+ virtual void Talk(const char *Text, const char *Sound = NULL, uint32 Duration = 0, const char *Stances = NULL, TTextAlign Align = TAL_CENTER);
+ virtual int GetHeight();
+ CAdSentence *_sentence;
+ HRESULT SetFont(const char *Filename);
+ virtual HRESULT Update();
+ virtual HRESULT Display();
+ bool _drawn;
+ bool _active;
+ virtual HRESULT PlayAnim(const char *Filename);
+ CBSprite *_animSprite;
+ CBSprite *_currentSprite;
+ TObjectState _state;
+ TObjectState _nextState;
+ TObjectType _type;
+ CAdObject(CBGame *inGame);
+ virtual ~CAdObject();
+ CBFont *_font;
+ CBSprite *_tempSprite2;
+ CBRegion *_blockRegion;
+ CAdWaypointGroup *_wptGroup;
+ CBRegion *_currentBlockRegion;
+ CAdWaypointGroup *_currentWptGroup;
+ CAdInventory *GetInventory();
+
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+
+ virtual HRESULT AfterMove();
+ CAdRegion *_currentRegions[MAX_NUM_REGIONS];
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+
+ CBArray<CAdObject *, CAdObject *> _attachmentsPre;
+ CBArray<CAdObject *, CAdObject *> _attachmentsPost;
+
+ HRESULT UpdateSpriteAttachments();
+ HRESULT DisplaySpriteAttachments(bool PreDisplay);
+ CAdObject *_registerAlias;
+private:
+ HRESULT DisplaySpriteAttachment(CAdObject *Attachment);
+ CAdInventory *_inventory;
+
+protected:
+ HRESULT GetScale(float *ScaleX, float *ScaleY);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdPath.cpp b/engines/wintermute/Ad/AdPath.cpp
new file mode 100644
index 0000000000..210f13f68b
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdPath.h"
+#include "engines/wintermute/BPoint.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdPath, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdPath::CAdPath(CBGame *inGame): CBBase(inGame) {
+ _currIndex = -1;
+ _ready = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdPath::~CAdPath() {
+ Reset();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdPath::Reset() {
+ for (int i = 0; i < _points.GetSize(); i++)
+ delete _points[i];
+
+ _points.RemoveAll();
+ _currIndex = -1;
+ _ready = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBPoint *CAdPath::GetFirst() {
+ if (_points.GetSize() > 0) {
+ _currIndex = 0;
+ return _points[_currIndex];
+ } else return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBPoint *CAdPath::GetNext() {
+ _currIndex++;
+ if (_currIndex < _points.GetSize()) return _points[_currIndex];
+ else return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBPoint *CAdPath::GetCurrent() {
+ if (_currIndex >= 0 && _currIndex < _points.GetSize()) return _points[_currIndex];
+ else return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdPath::AddPoint(CBPoint *point) {
+ _points.Add(point);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdPath::SetReady(bool ready) {
+ bool orig = _ready;
+ _ready = ready;
+
+ return orig;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdPath::Persist(CBPersistMgr *PersistMgr) {
+
+ PersistMgr->Transfer(TMEMBER(Game));
+
+ PersistMgr->Transfer(TMEMBER(_currIndex));
+ _points.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_ready));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdPath.h b/engines/wintermute/Ad/AdPath.h
new file mode 100644
index 0000000000..d921e78c0a
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADPATH_H
+#define WINTERMUTE_ADPATH_H
+
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/coll_templ.h"
+#include "engines/wintermute/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 *> _points;
+ int _currIndex;
+ bool _ready;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdPathPoint.cpp b/engines/wintermute/Ad/AdPathPoint.cpp
new file mode 100644
index 0000000000..c66a7769f5
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/Ad/AdPathPoint.h"
+#include "engines/wintermute/BPersistMgr.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdPathPoint, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdPathPoint::CAdPathPoint() {
+ x = y = 0;
+ _distance = 0;
+
+ _marked = false;
+ _origin = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdPathPoint::CAdPathPoint(int initX, int initY, int initDistance) {
+ x = initX;
+ y = initY;
+ _distance = initDistance;
+
+ _marked = false;
+ _origin = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdPathPoint::~CAdPathPoint() {
+ _origin = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdPathPoint::Persist(CBPersistMgr *PersistMgr) {
+
+ CBPoint::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_distance));
+ PersistMgr->Transfer(TMEMBER(_marked));
+ PersistMgr->Transfer(TMEMBER(_origin));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdPathPoint.h b/engines/wintermute/Ad/AdPathPoint.h
new file mode 100644
index 0000000000..bb31223dbb
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADPATHPOINT_H
+#define WINTERMUTE_ADPATHPOINT_H
+
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/BPoint.h"
+
+namespace WinterMute {
+
+class CAdPathPoint : public CBPoint {
+public:
+ DECLARE_PERSISTENT(CAdPathPoint, CBPoint)
+ CAdPathPoint(int initX, int initY, int initDistance);
+ CAdPathPoint();
+ virtual ~CAdPathPoint();
+ CAdPathPoint *_origin;
+ bool _marked;
+ int _distance;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdRegion.cpp b/engines/wintermute/Ad/AdRegion.cpp
new file mode 100644
index 0000000000..41022a85aa
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdRegion.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdRegion, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdRegion::CAdRegion(CBGame *inGame): CBRegion(inGame) {
+ _blocked = false;
+ _decoration = false;
+ _zoom = 0;
+ _alpha = 0xFFFFFFFF;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdRegion::~CAdRegion() {
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdRegion::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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 < _points.GetSize(); i++) delete _points[i];
+ _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", &_active);
+ break;
+
+ case TOKEN_BLOCKED:
+ parser.ScanStr((char *)params, "%b", &_blocked);
+ break;
+
+ case TOKEN_DECORATION:
+ parser.ScanStr((char *)params, "%b", &_decoration);
+ break;
+
+ case TOKEN_ZOOM:
+ case TOKEN_SCALE: {
+ int i;
+ parser.ScanStr((char *)params, "%d", &i);
+ _zoom = (float)i;
+ }
+ break;
+
+ case TOKEN_POINT: {
+ int x, y;
+ parser.ScanStr((char *)params, "%d,%d", &x, &y);
+ _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", &_editorSelected);
+ break;
+
+ case TOKEN_EDITOR_SELECTED_POINT:
+ parser.ScanStr((char *)params, "%d", &_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();
+
+ _alpha = DRGBA(ar, ag, ab, alpha);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name) {
+ /*
+ //////////////////////////////////////////////////////////////////////////
+ // SkipTo
+ //////////////////////////////////////////////////////////////////////////
+ if(strcmp(Name, "SkipTo")==0){
+ Stack->CorrectParams(2);
+ _posX = Stack->Pop()->GetInt();
+ _posY = Stack->Pop()->GetInt();
+ Stack->PushNULL();
+
+ return S_OK;
+ }
+
+ else*/ return CBRegion::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdRegion::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("ad region");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Name") == 0) {
+ _scValue->SetString(_name);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Blocked
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Blocked") == 0) {
+ _scValue->SetBool(_blocked);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Decoration
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Decoration") == 0) {
+ _scValue->SetBool(_decoration);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Scale
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale") == 0) {
+ _scValue->SetFloat(_zoom);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AlphaColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AlphaColor") == 0) {
+ _scValue->SetInt((int)_alpha);
+ return _scValue;
+ }
+
+ else return CBRegion::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRegion::ScSetProperty(const char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Blocked
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Blocked") == 0) {
+ _blocked = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Decoration
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Decoration") == 0) {
+ _decoration = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Scale
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale") == 0) {
+ _zoom = Value->GetFloat();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AlphaColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AlphaColor") == 0) {
+ _alpha = (uint32)Value->GetInt();
+ return S_OK;
+ }
+
+ else return CBRegion::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const 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", _name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+ Buffer->PutTextIndent(Indent + 2, "BLOCKED=%s\n", _blocked ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "DECORATION=%s\n", _decoration ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "ACTIVE=%s\n", _active ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "SCALE=%d\n", (int)_zoom);
+ Buffer->PutTextIndent(Indent + 2, "ALPHA_COLOR { %d,%d,%d }\n", D3DCOLGetR(_alpha), D3DCOLGetG(_alpha), D3DCOLGetB(_alpha));
+ Buffer->PutTextIndent(Indent + 2, "ALPHA = %d\n", D3DCOLGetA(_alpha));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", _editorSelected ? "TRUE" : "FALSE");
+
+ int i;
+ for (i = 0; i < _scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ if (_scProp) _scProp->SaveAsText(Buffer, Indent + 2);
+
+ for (i = 0; i < _points.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "POINT {%d,%d}\n", _points[i]->x, _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(_alpha));
+ PersistMgr->Transfer(TMEMBER(_blocked));
+ PersistMgr->Transfer(TMEMBER(_decoration));
+ PersistMgr->Transfer(TMEMBER(_zoom));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdRegion.h b/engines/wintermute/Ad/AdRegion.h
new file mode 100644
index 0000000000..37be803a9e
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADREGION_H
+#define WINTERMUTE_ADREGION_H
+
+#include "engines/wintermute/BRegion.h"
+
+namespace WinterMute {
+
+class CAdRegion : public CBRegion {
+public:
+ DECLARE_PERSISTENT(CAdRegion, CBRegion)
+ uint32 _alpha;
+ float _zoom;
+ bool _blocked;
+ bool _decoration;
+ CAdRegion(CBGame *inGame);
+ virtual ~CAdRegion();
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdResponse.cpp b/engines/wintermute/Ad/AdResponse.cpp
new file mode 100644
index 0000000000..3db37385b6
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdResponse.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BFontStorage.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/utils.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdResponse, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponse::CAdResponse(CBGame *inGame): CBObject(inGame) {
+ _text = NULL;
+ _textOrig = NULL;
+ _icon = _iconHover = _iconPressed = NULL;
+ _font = NULL;
+ _iD = 0;
+ _responseType = RESPONSE_ALWAYS;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponse::~CAdResponse() {
+ delete[] _text;
+ delete[] _textOrig;
+ delete _icon;
+ delete _iconHover;
+ delete _iconPressed;
+ _text = NULL;
+ _textOrig = NULL;
+ _icon = NULL;
+ _iconHover = NULL;
+ _iconPressed = NULL;
+ if (_font) Game->_fontStorage->RemoveFont(_font);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponse::SetText(const char *Text) {
+ CBUtils::SetString(&_text, Text);
+ CBUtils::SetString(&_textOrig, Text);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetIcon(const char *Filename) {
+ delete _icon;
+ _icon = new CBSprite(Game);
+ if (!_icon || FAILED(_icon->LoadFile(Filename))) {
+ Game->LOG(0, "CAdResponse::SetIcon failed for file '%s'", Filename);
+ delete _icon;
+ _icon = NULL;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetFont(const char *Filename) {
+ if (_font) Game->_fontStorage->RemoveFont(_font);
+ _font = Game->_fontStorage->AddFont(Filename);
+ if (!_font) {
+ Game->LOG(0, "CAdResponse::SetFont failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetIconHover(const char *Filename) {
+ delete _iconHover;
+ _iconHover = new CBSprite(Game);
+ if (!_iconHover || FAILED(_iconHover->LoadFile(Filename))) {
+ Game->LOG(0, "CAdResponse::SetIconHover failed for file '%s'", Filename);
+ delete _iconHover;
+ _iconHover = NULL;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::SetIconPressed(const char *Filename) {
+ delete _iconPressed;
+ _iconPressed = new CBSprite(Game);
+ if (!_iconPressed || FAILED(_iconPressed->LoadFile(Filename))) {
+ Game->LOG(0, "CAdResponse::SetIconPressed failed for file '%s'", Filename);
+ delete _iconPressed;
+ _iconPressed = NULL;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponse::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_icon));
+ PersistMgr->Transfer(TMEMBER(_iconHover));
+ PersistMgr->Transfer(TMEMBER(_iconPressed));
+ PersistMgr->Transfer(TMEMBER(_iD));
+ PersistMgr->Transfer(TMEMBER(_text));
+ PersistMgr->Transfer(TMEMBER(_textOrig));
+ PersistMgr->Transfer(TMEMBER_INT(_responseType));
+ PersistMgr->Transfer(TMEMBER(_font));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdResponse.h b/engines/wintermute/Ad/AdResponse.h
new file mode 100644
index 0000000000..88f6fc03a8
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADRESPONSE_H
+#define WINTERMUTE_ADRESPONSE_H
+
+
+#include "engines/wintermute/BObject.h"
+#include "engines/wintermute/Ad/AdTypes.h"
+
+namespace WinterMute {
+class CBFont;
+class CAdResponse : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdResponse, CBObject)
+ HRESULT SetIcon(const char *Filename);
+ HRESULT SetFont(const char *Filename);
+ HRESULT SetIconHover(const char *Filename);
+ HRESULT SetIconPressed(const char *Filename);
+ void SetText(const char *Text);
+ int _iD;
+ CBSprite *_icon;
+ CBSprite *_iconHover;
+ CBSprite *_iconPressed;
+ CBFont *_font;
+ char *_text;
+ char *_textOrig;
+ CAdResponse(CBGame *inGame);
+ virtual ~CAdResponse();
+ TResponseType _responseType;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdResponseBox.cpp b/engines/wintermute/Ad/AdResponseBox.cpp
new file mode 100644
index 0000000000..d50e25e088
--- /dev/null
+++ b/engines/wintermute/Ad/AdResponseBox.cpp
@@ -0,0 +1,645 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdResponseBox.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BSurfaceStorage.h"
+#include "engines/wintermute/UIButton.h"
+#include "engines/wintermute/UIWindow.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BFontStorage.h"
+#include "engines/wintermute/BFont.h"
+#include "engines/wintermute/Ad/AdResponse.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/utils.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdResponseBox, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseBox::CAdResponseBox(CBGame *inGame): CBObject(inGame) {
+ _font = _fontHover = NULL;
+
+ _window = NULL;
+ _shieldWindow = new CUIWindow(Game);
+
+ _horizontal = false;
+ CBPlatform::SetRectEmpty(&_responseArea);
+ _scrollOffset = 0;
+ _spacing = 0;
+
+ _waitingScript = NULL;
+ _lastResponseText = NULL;
+ _lastResponseTextOrig = NULL;
+
+ _verticalAlign = VAL_BOTTOM;
+ _align = TAL_LEFT;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseBox::~CAdResponseBox() {
+
+ delete _window;
+ _window = NULL;
+ delete _shieldWindow;
+ _shieldWindow = NULL;
+ delete[] _lastResponseText;
+ _lastResponseText = NULL;
+ delete[] _lastResponseTextOrig;
+ _lastResponseTextOrig = NULL;
+
+ if (_font) Game->_fontStorage->RemoveFont(_font);
+ if (_fontHover) Game->_fontStorage->RemoveFont(_fontHover);
+
+ ClearResponses();
+ ClearButtons();
+
+ _waitingScript = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseBox::ClearResponses() {
+ for (int i = 0; i < _responses.GetSize(); i++) {
+ delete _responses[i];
+ }
+ _responses.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseBox::ClearButtons() {
+ for (int i = 0; i < _respButtons.GetSize(); i++) {
+ delete _respButtons[i];
+ }
+ _respButtons.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::InvalidateButtons() {
+ for (int i = 0; i < _respButtons.GetSize(); i++) {
+ _respButtons[i]->_image = NULL;
+ _respButtons[i]->_cursor = NULL;
+ _respButtons[i]->_font = NULL;
+ _respButtons[i]->_fontHover = NULL;
+ _respButtons[i]->_fontPress = NULL;
+ _respButtons[i]->SetText("");
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::CreateButtons() {
+ ClearButtons();
+
+ _scrollOffset = 0;
+ for (int i = 0; i < _responses.GetSize(); i++) {
+ CUIButton *btn = new CUIButton(Game);
+ if (btn) {
+ btn->_parent = _window;
+ btn->_sharedFonts = btn->_sharedImages = true;
+ btn->_sharedCursors = true;
+ // iconic
+ if (_responses[i]->_icon) {
+ btn->_image = _responses[i]->_icon;
+ if (_responses[i]->_iconHover) btn->_imageHover = _responses[i]->_iconHover;
+ if (_responses[i]->_iconPressed) btn->_imagePress = _responses[i]->_iconPressed;
+
+ btn->SetCaption(_responses[i]->_text);
+ if (_cursor) btn->_cursor = _cursor;
+ else if (Game->_activeCursor) btn->_cursor = Game->_activeCursor;
+ }
+ // textual
+ else {
+ btn->SetText(_responses[i]->_text);
+ btn->_font = (_font == NULL) ? Game->_systemFont : _font;
+ btn->_fontHover = (_fontHover == NULL) ? Game->_systemFont : _fontHover;
+ btn->_fontPress = btn->_fontHover;
+ btn->_align = _align;
+
+ if (Game->_touchInterface)
+ btn->_fontHover = btn->_font;
+
+
+ if (_responses[i]->_font) btn->_font = _responses[i]->_font;
+
+ btn->_width = _responseArea.right - _responseArea.left;
+ if (btn->_width <= 0) btn->_width = Game->_renderer->_width;
+ }
+ btn->SetName("response");
+ btn->CorrectSize();
+
+ // make the responses touchable
+ if (Game->_touchInterface)
+ btn->_height = MAX(btn->_height, 50);
+
+ //btn->SetListener(this, btn, _responses[i]->_iD);
+ btn->SetListener(this, btn, i);
+ btn->_visible = false;
+ _respButtons.Add(btn);
+
+ if (_responseArea.bottom - _responseArea.top < btn->_height) {
+ Game->LOG(0, "Warning: Response '%s' is too high to be displayed within response box. Correcting.", _responses[i]->_text);
+ _responseArea.bottom += (btn->_height - (_responseArea.bottom - _responseArea.top));
+ }
+ }
+ }
+ _ready = false;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdResponseBox::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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:
+ delete _window;
+ _window = new CUIWindow(Game);
+ if (!_window || FAILED(_window->LoadBuffer(params, false))) {
+ delete _window;
+ _window = NULL;
+ cmd = PARSERR_GENERIC;
+ } else if (_shieldWindow) _shieldWindow->_parent = _window;
+ break;
+
+ case TOKEN_FONT:
+ if (_font) Game->_fontStorage->RemoveFont(_font);
+ _font = Game->_fontStorage->AddFont((char *)params);
+ if (!_font) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_HOVER:
+ if (_fontHover) Game->_fontStorage->RemoveFont(_fontHover);
+ _fontHover = Game->_fontStorage->AddFont((char *)params);
+ if (!_fontHover) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_AREA:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &_responseArea.left, &_responseArea.top, &_responseArea.right, &_responseArea.bottom);
+ break;
+
+ case TOKEN_HORIZONTAL:
+ parser.ScanStr((char *)params, "%b", &_horizontal);
+ break;
+
+ case TOKEN_TEXT_ALIGN:
+ if (scumm_stricmp((char *)params, "center") == 0) _align = TAL_CENTER;
+ else if (scumm_stricmp((char *)params, "right") == 0) _align = TAL_RIGHT;
+ else _align = TAL_LEFT;
+ break;
+
+ case TOKEN_VERTICAL_ALIGN:
+ if (scumm_stricmp((char *)params, "top") == 0) _verticalAlign = VAL_TOP;
+ else if (scumm_stricmp((char *)params, "center") == 0) _verticalAlign = VAL_CENTER;
+ else _verticalAlign = VAL_BOTTOM;
+ break;
+
+ case TOKEN_SPACING:
+ parser.ScanStr((char *)params, "%d", &_spacing);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ ParseEditorProperty(params, false);
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursor;
+ _cursor = new CBSprite(Game);
+ if (!_cursor || FAILED(_cursor->LoadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ Game->LOG(0, "Syntax error in RESPONSE_BOX definition");
+ return E_FAIL;
+ }
+
+ if (_window) {
+ for (int i = 0; i < _window->_widgets.GetSize(); i++) {
+ if (!_window->_widgets[i]->_listenerObject)
+ _window->_widgets[i]->SetListener(this, _window->_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", _responseArea.left, _responseArea.top, _responseArea.right, _responseArea.bottom);
+
+ if (_font && _font->_filename)
+ Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", _font->_filename);
+ if (_fontHover && _fontHover->_filename)
+ Buffer->PutTextIndent(Indent + 2, "FONT_HOVER=\"%s\"\n", _fontHover->_filename);
+
+ if (_cursor && _cursor->_filename)
+ Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", _cursor->_filename);
+
+ Buffer->PutTextIndent(Indent + 2, "HORIZONTAL=%s\n", _horizontal ? "TRUE" : "FALSE");
+
+ switch (_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;
+ default:
+ error("CAdResponseBox::SaveAsText - Unhandled enum");
+ break;
+ }
+
+ switch (_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", _spacing);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // window
+ if (_window) _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 = _responseArea;
+ if (_window) {
+ CBPlatform::OffsetRect(&rect, _window->_posX, _window->_posY);
+ //_window->Display();
+ }
+
+ int xxx, yyy, i;
+
+ xxx = rect.left;
+ yyy = rect.top;
+
+ // shift down if needed
+ if (!_horizontal) {
+ int total_height = 0;
+ for (i = 0; i < _respButtons.GetSize(); i++) total_height += (_respButtons[i]->_height + _spacing);
+ total_height -= _spacing;
+
+ switch (_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 = _scrollOffset; i < _respButtons.GetSize(); i++) {
+ if ((_horizontal && xxx + _respButtons[i]->_width > rect.right)
+ || (!_horizontal && yyy + _respButtons[i]->_height > rect.bottom)) {
+
+ scroll_needed = true;
+ _respButtons[i]->_visible = false;
+ break;
+ }
+
+ _respButtons[i]->_visible = true;
+ _respButtons[i]->_posX = xxx;
+ _respButtons[i]->_posY = yyy;
+
+ if (_horizontal) {
+ xxx += (_respButtons[i]->_width + _spacing);
+ } else {
+ yyy += (_respButtons[i]->_height + _spacing);
+ }
+ }
+
+ // show appropriate scroll buttons
+ if (_window) {
+ _window->ShowWidget("prev", _scrollOffset > 0);
+ _window->ShowWidget("next", scroll_needed);
+ }
+
+ // go exclusive
+ if (_shieldWindow) {
+ _shieldWindow->_posX = _shieldWindow->_posY = 0;
+ _shieldWindow->_width = Game->_renderer->_width;
+ _shieldWindow->_height = Game->_renderer->_height;
+
+ _shieldWindow->Display();
+ }
+
+ // display window
+ if (_window) _window->Display();
+
+
+ // display response buttons
+ for (i = _scrollOffset; i < _respButtons.GetSize(); i++) {
+ _respButtons[i]->Display();
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::Listen(CBScriptHolder *param1, uint32 param2) {
+ CUIObject *obj = (CUIObject *)param1;
+
+ switch (obj->_type) {
+ case UI_BUTTON:
+ if (scumm_stricmp(obj->_name, "prev") == 0) {
+ _scrollOffset--;
+ } else if (scumm_stricmp(obj->_name, "next") == 0) {
+ _scrollOffset++;
+ } else if (scumm_stricmp(obj->_name, "response") == 0) {
+ if (_waitingScript) _waitingScript->_stack->PushInt(_responses[param2]->_iD);
+ HandleResponse(_responses[param2]);
+ _waitingScript = NULL;
+ Game->_state = GAME_RUNNING;
+ ((CAdGame *)Game)->_stateEx = GAME_NORMAL;
+ _ready = true;
+ InvalidateButtons();
+ ClearResponses();
+ } else return CBObject::Listen(param1, param2);
+ break;
+ default:
+ error("AdResponseBox::Listen - Unhandled enum");
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_font));
+ PersistMgr->Transfer(TMEMBER(_fontHover));
+ PersistMgr->Transfer(TMEMBER(_horizontal));
+ PersistMgr->Transfer(TMEMBER(_lastResponseText));
+ PersistMgr->Transfer(TMEMBER(_lastResponseTextOrig));
+ _respButtons.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_responseArea));
+ _responses.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_scrollOffset));
+ PersistMgr->Transfer(TMEMBER(_shieldWindow));
+ PersistMgr->Transfer(TMEMBER(_spacing));
+ PersistMgr->Transfer(TMEMBER(_waitingScript));
+ PersistMgr->Transfer(TMEMBER(_window));
+
+ PersistMgr->Transfer(TMEMBER_INT(_verticalAlign));
+ PersistMgr->Transfer(TMEMBER_INT(_align));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::WeedResponses() {
+ CAdGame *AdGame = (CAdGame *)Game;
+
+ for (int i = 0; i < _responses.GetSize(); i++) {
+ switch (_responses[i]->_responseType) {
+ case RESPONSE_ONCE:
+ if (AdGame->BranchResponseUsed(_responses[i]->_iD)) {
+ delete _responses[i];
+ _responses.RemoveAt(i);
+ i--;
+ }
+ break;
+
+ case RESPONSE_ONCE_GAME:
+ if (AdGame->GameResponseUsed(_responses[i]->_iD)) {
+ delete _responses[i];
+ _responses.RemoveAt(i);
+ i--;
+ }
+ break;
+ default:
+ error("CAdResponseBox::WeedResponses - Unhandled enum");
+ break;
+ }
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseBox::SetLastResponseText(const char *Text, const char *TextOrig) {
+ CBUtils::SetString(&_lastResponseText, Text);
+ CBUtils::SetString(&_lastResponseTextOrig, TextOrig);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseBox::HandleResponse(CAdResponse *Response) {
+ SetLastResponseText(Response->_text, Response->_textOrig);
+
+ CAdGame *AdGame = (CAdGame *)Game;
+
+ switch (Response->_responseType) {
+ case RESPONSE_ONCE:
+ AdGame->AddBranchResponse(Response->_iD);
+ break;
+
+ case RESPONSE_ONCE_GAME:
+ AdGame->AddGameResponse(Response->_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 < _respButtons.GetSize(); i++) {
+ Objects.Add(_respButtons[i]);
+ }
+ if (_window) _window->GetWindowObjects(Objects, InteractiveOnly);
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdResponseBox.h b/engines/wintermute/Ad/AdResponseBox.h
new file mode 100644
index 0000000000..cf98cfadca
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADRESPONSEBOX_H
+#define WINTERMUTE_ADRESPONSEBOX_H
+
+
+#include "engines/wintermute/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(const char *Text, const char *TextOrig);
+ char *_lastResponseText;
+ char *_lastResponseTextOrig;
+ DECLARE_PERSISTENT(CAdResponseBox, CBObject)
+ CScScript *_waitingScript;
+ virtual HRESULT Listen(CBScriptHolder *param1, uint32 param2);
+ typedef enum {
+ EVENT_PREV, EVENT_NEXT, EVENT_RESPONSE
+ } TResponseEvent;
+
+ HRESULT WeedResponses();
+ HRESULT Display();
+ int _spacing;
+ int _scrollOffset;
+ CBFont *_fontHover;
+ CBFont *_font;
+ HRESULT CreateButtons();
+ HRESULT InvalidateButtons();
+ void ClearButtons();
+ void ClearResponses();
+ CAdResponseBox(CBGame *inGame);
+ virtual ~CAdResponseBox();
+ CBArray<CAdResponse *, CAdResponse *> _responses;
+ CBArray<CUIButton *, CUIButton *> _respButtons;
+ CUIWindow *_window;
+ CUIWindow *_shieldWindow;
+ bool _horizontal;
+ RECT _responseArea;
+ int _verticalAlign;
+ TTextAlign _align;
+ HRESULT LoadFile(const 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/Ad/AdResponseContext.cpp b/engines/wintermute/Ad/AdResponseContext.cpp
new file mode 100644
index 0000000000..482edbcb4d
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdResponseContext.h"
+#include "engines/wintermute/BPersistMgr.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdResponseContext, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseContext::CAdResponseContext(CBGame *inGame): CBBase(inGame) {
+ _iD = 0;
+ _context = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdResponseContext::~CAdResponseContext() {
+ delete[] _context;
+ _context = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdResponseContext::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(Game));
+ PersistMgr->Transfer(TMEMBER(_context));
+ PersistMgr->Transfer(TMEMBER(_iD));
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+void CAdResponseContext::SetContext(const char *Context) {
+ delete[] _context;
+ _context = NULL;
+ if (Context) {
+ _context = new char [strlen(Context) + 1];
+ if (_context) strcpy(_context, Context);
+ }
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdResponseContext.h b/engines/wintermute/Ad/AdResponseContext.h
new file mode 100644
index 0000000000..84ca44ef6f
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADRESPONSECONTEXT_H
+#define WINTERMUTE_ADRESPONSECONTEXT_H
+
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/BBase.h"
+
+namespace WinterMute {
+
+class CAdResponseContext : public CBBase {
+public:
+ void SetContext(const char *Context);
+ int _iD;
+ char *_context;
+ DECLARE_PERSISTENT(CAdResponseContext, CBBase)
+ CAdResponseContext(CBGame *inGame);
+ virtual ~CAdResponseContext();
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdRotLevel.cpp b/engines/wintermute/Ad/AdRotLevel.cpp
new file mode 100644
index 0000000000..ea1681660a
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdRotLevel.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdRotLevel, false)
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdRotLevel::CAdRotLevel(CBGame *inGame): CBObject(inGame) {
+ _posX = 0;
+ _rotation = 0.0f;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdRotLevel::~CAdRotLevel() {
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRotLevel::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdRotLevel::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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", &_posX);
+ break;
+
+ case TOKEN_ROTATION: {
+ int i;
+ parser.ScanStr((char *)params, "%d", &i);
+ _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", _posX);
+ Buffer->PutTextIndent(Indent + 2, "ROTATION=%d\n", (int)_rotation);
+ CBBase::SaveAsText(Buffer, Indent + 2);
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdRotLevel::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_rotation));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdRotLevel.h b/engines/wintermute/Ad/AdRotLevel.h
new file mode 100644
index 0000000000..dd3b318a34
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADROTLEVEL_H
+#define WINTERMUTE_ADROTLEVEL_H
+
+#include "engines/wintermute/BObject.h"
+
+namespace WinterMute {
+
+class CAdRotLevel : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdRotLevel, CBObject)
+ CAdRotLevel(CBGame *inGame);
+ virtual ~CAdRotLevel();
+ float _rotation;
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdScaleLevel.cpp b/engines/wintermute/Ad/AdScaleLevel.cpp
new file mode 100644
index 0000000000..06729c6435
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdScaleLevel.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdScaleLevel, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdScaleLevel::CAdScaleLevel(CBGame *inGame): CBObject(inGame) {
+ _posY = 0;
+ _scale = 100;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdScaleLevel::~CAdScaleLevel() {
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScaleLevel::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdScaleLevel::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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", &_posY);
+ break;
+
+ case TOKEN_SCALE: {
+ int i;
+ parser.ScanStr((char *)params, "%d", &i);
+ _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", _posY);
+ Buffer->PutTextIndent(Indent + 2, "SCALE=%d\n", (int)_scale);
+ CBBase::SaveAsText(Buffer, Indent + 2);
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScaleLevel::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_scale));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdScaleLevel.h b/engines/wintermute/Ad/AdScaleLevel.h
new file mode 100644
index 0000000000..9cda5cf4d0
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADSCALELEVEL_H
+#define WINTERMUTE_ADSCALELEVEL_H
+
+
+#include "engines/wintermute/BObject.h"
+
+namespace WinterMute {
+
+class CAdScaleLevel : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdScaleLevel, CBObject)
+ float _scale;
+ CAdScaleLevel(CBGame *inGame);
+ virtual ~CAdScaleLevel();
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdScene.cpp b/engines/wintermute/Ad/AdScene.cpp
new file mode 100644
index 0000000000..f7cd60c555
--- /dev/null
+++ b/engines/wintermute/Ad/AdScene.cpp
@@ -0,0 +1,2763 @@
+/* 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 "engines/wintermute/Ad/AdScene.h"
+#include "engines/wintermute/Ad/AdActor.h"
+#include "engines/wintermute/Ad/AdEntity.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/Ad/AdLayer.h"
+#include "engines/wintermute/Ad/AdNodeState.h"
+#include "engines/wintermute/Ad/AdObject.h"
+#include "engines/wintermute/Ad/AdPath.h"
+#include "engines/wintermute/Ad/AdPathPoint.h"
+#include "engines/wintermute/Ad/AdRotLevel.h"
+#include "engines/wintermute/Ad/AdScaleLevel.h"
+#include "engines/wintermute/Ad/AdSceneNode.h"
+#include "engines/wintermute/Ad/AdSceneState.h"
+#include "engines/wintermute/Ad/AdSentence.h"
+#include "engines/wintermute/Ad/AdWaypointGroup.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/BFont.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BObject.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BPoint.h"
+#include "engines/wintermute/BRegion.h"
+#include "engines/wintermute/BScriptable.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BViewport.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/UIWindow.h"
+#include "engines/wintermute/utils.h"
+#include <math.h>
+#include <limits.h>
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdScene, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdScene::CAdScene(CBGame *inGame): CBObject(inGame) {
+ _pFTarget = new CBPoint;
+ SetDefaults();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdScene::~CAdScene() {
+ Cleanup();
+ Game->UnregisterObject(_fader);
+ delete _pFTarget;
+ _pFTarget = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::SetDefaults() {
+ _initialized = false;
+ _pFReady = true;
+ _pFTargetPath = NULL;
+ _pFRequester = NULL;
+ _mainLayer = NULL;
+
+ _pFPointsNum = 0;
+ _persistentState = false;
+ _persistentStateSprites = true;
+
+ _autoScroll = true;
+ _offsetLeft = _offsetTop = 0;
+ _targetOffsetLeft = _targetOffsetTop = 0;
+
+ _lastTimeH = _lastTimeV = 0;
+ _scrollTimeH = _scrollTimeV = 10;
+ _scrollPixelsH = _scrollPixelsV = 1;
+
+ _pFMaxTime = 15;
+
+ _paralaxScrolling = true;
+
+ // editor settings
+ _editorMarginH = _editorMarginV = 100;
+
+ _editorColFrame = 0xE0888888;
+ _editorColEntity = 0xFF008000;
+ _editorColRegion = 0xFF0000FF;
+ _editorColBlocked = 0xFF800080;
+ _editorColWaypoints = 0xFF0000FF;
+ _editorColEntitySel = 0xFFFF0000;
+ _editorColRegionSel = 0xFFFF0000;
+ _editorColBlockedSel = 0xFFFF0000;
+ _editorColWaypointsSel = 0xFFFF0000;
+ _editorColScale = 0xFF00FF00;
+ _editorColDecor = 0xFF00FFFF;
+ _editorColDecorSel = 0xFFFF0000;
+
+ _editorShowRegions = true;
+ _editorShowBlocked = true;
+ _editorShowDecor = true;
+ _editorShowEntities = true;
+ _editorShowScale = true;
+
+ _shieldWindow = NULL;
+
+ _fader = new CBFader(Game);
+ Game->RegisterObject(_fader);
+
+ _viewport = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::Cleanup() {
+ CBObject::Cleanup();
+
+ _mainLayer = NULL; // reference only
+
+ int i;
+
+ delete _shieldWindow;
+ _shieldWindow = NULL;
+
+ Game->UnregisterObject(_fader);
+ _fader = NULL;
+
+ for (i = 0; i < _layers.GetSize(); i++)
+ Game->UnregisterObject(_layers[i]);
+ _layers.RemoveAll();
+
+
+ for (i = 0; i < _waypointGroups.GetSize(); i++)
+ Game->UnregisterObject(_waypointGroups[i]);
+ _waypointGroups.RemoveAll();
+
+ for (i = 0; i < _scaleLevels.GetSize(); i++)
+ Game->UnregisterObject(_scaleLevels[i]);
+ _scaleLevels.RemoveAll();
+
+ for (i = 0; i < _rotLevels.GetSize(); i++)
+ Game->UnregisterObject(_rotLevels[i]);
+ _rotLevels.RemoveAll();
+
+
+ for (i = 0; i < _pFPath.GetSize(); i++)
+ delete _pFPath[i];
+ _pFPath.RemoveAll();
+ _pFPointsNum = 0;
+
+ for (i = 0; i < _objects.GetSize(); i++)
+ Game->UnregisterObject(_objects[i]);
+ _objects.RemoveAll();
+
+ delete _viewport;
+ _viewport = NULL;
+
+ SetDefaults();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdScene::GetPath(CBPoint source, CBPoint target, CAdPath *path, CBObject *requester) {
+ if (!_pFReady) return false;
+ else {
+ _pFReady = false;
+ *_pFTarget = target;
+ _pFTargetPath = path;
+ _pFRequester = requester;
+
+ _pFTargetPath->Reset();
+ _pFTargetPath->SetReady(false);
+
+ // prepare working path
+ int i;
+ PFPointsStart();
+
+ // first point
+ //_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
+ //_pFPath.Add(new CAdPathPoint(target.x, target.y, INT_MAX));
+ PFPointsAdd(target.x, target.y, INT_MAX);
+
+ // active waypoints
+ for (i = 0; i < _waypointGroups.GetSize(); i++) {
+ if (_waypointGroups[i]->_active) {
+ PFAddWaypointGroup(_waypointGroups[i], requester);
+ }
+ }
+
+
+ // free waypoints
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i]->_active && _objects[i] != requester && _objects[i]->_currentWptGroup) {
+ PFAddWaypointGroup(_objects[i]->_currentWptGroup, requester);
+ }
+ }
+ CAdGame *AdGame = (CAdGame *)Game;
+ for (i = 0; i < AdGame->_objects.GetSize(); i++) {
+ if (AdGame->_objects[i]->_active && AdGame->_objects[i] != requester && AdGame->_objects[i]->_currentWptGroup) {
+ PFAddWaypointGroup(AdGame->_objects[i]->_currentWptGroup, requester);
+ }
+ }
+
+ return true;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::PFAddWaypointGroup(CAdWaypointGroup *Wpt, CBObject *Requester) {
+ if (!Wpt->_active) return;
+
+ for (int i = 0; i < Wpt->_points.GetSize(); i++) {
+ if (IsBlockedAt(Wpt->_points[i]->x, Wpt->_points[i]->y, true, Requester)) continue;
+
+ //_pFPath.Add(new CAdPathPoint(Wpt->_points[i]->x, Wpt->_points[i]->y, INT_MAX));
+ PFPointsAdd(Wpt->_points[i]->x, Wpt->_points[i]->y, INT_MAX);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+float CAdScene::GetZoomAt(int X, int Y) {
+ float ret = 100;
+
+ bool found = false;
+ if (_mainLayer) {
+ for (int i = _mainLayer->_nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = _mainLayer->_nodes[i];
+ if (Node->_type == OBJECT_REGION && Node->_region->_active && !Node->_region->_blocked && Node->_region->PointInRegion(X, Y)) {
+ if (Node->_region->_zoom != 0) {
+ ret = Node->_region->_zoom;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!found) ret = GetScaleAt(Y);
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CAdScene::GetAlphaAt(int X, int Y, bool ColorCheck) {
+ if (!Game->_dEBUG_DebugMode) ColorCheck = false;
+
+ uint32 ret;
+ if (ColorCheck) ret = 0xFFFF0000;
+ else ret = 0xFFFFFFFF;
+
+ if (_mainLayer) {
+ for (int i = _mainLayer->_nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = _mainLayer->_nodes[i];
+ if (Node->_type == OBJECT_REGION && Node->_region->_active && (ColorCheck || !Node->_region->_blocked) && Node->_region->PointInRegion(X, Y)) {
+ if (!Node->_region->_blocked) ret = Node->_region->_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 < _objects.GetSize(); i++) {
+ if (_objects[i]->_active && _objects[i] != Requester && _objects[i]->_currentBlockRegion) {
+ if (_objects[i]->_currentBlockRegion->PointInRegion(X, Y)) return true;
+ }
+ }
+ CAdGame *AdGame = (CAdGame *)Game;
+ for (i = 0; i < AdGame->_objects.GetSize(); i++) {
+ if (AdGame->_objects[i]->_active && AdGame->_objects[i] != Requester && AdGame->_objects[i]->_currentBlockRegion) {
+ if (AdGame->_objects[i]->_currentBlockRegion->PointInRegion(X, Y)) return true;
+ }
+ }
+ }
+
+
+ if (_mainLayer) {
+ for (int i = 0; i < _mainLayer->_nodes.GetSize(); i++) {
+ CAdSceneNode *Node = _mainLayer->_nodes[i];
+ /*
+ if(Node->_type == OBJECT_REGION && Node->_region->_active && Node->_region->_blocked && Node->_region->PointInRegion(X, Y))
+ {
+ ret = true;
+ break;
+ }
+ */
+ if (Node->_type == OBJECT_REGION && Node->_region->_active && !Node->_region->_decoration && Node->_region->PointInRegion(X, Y)) {
+ if (Node->_region->_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 < _objects.GetSize(); i++) {
+ if (_objects[i]->_active && _objects[i] != Requester && _objects[i]->_currentBlockRegion) {
+ if (_objects[i]->_currentBlockRegion->PointInRegion(X, Y)) return false;
+ }
+ }
+ CAdGame *AdGame = (CAdGame *)Game;
+ for (i = 0; i < AdGame->_objects.GetSize(); i++) {
+ if (AdGame->_objects[i]->_active && AdGame->_objects[i] != Requester && AdGame->_objects[i]->_currentBlockRegion) {
+ if (AdGame->_objects[i]->_currentBlockRegion->PointInRegion(X, Y)) return false;
+ }
+ }
+ }
+
+
+ if (_mainLayer) {
+ for (int i = 0; i < _mainLayer->_nodes.GetSize(); i++) {
+ CAdSceneNode *Node = _mainLayer->_nodes[i];
+ if (Node->_type == OBJECT_REGION && Node->_region->_active && !Node->_region->_decoration && Node->_region->PointInRegion(X, Y)) {
+ if (Node->_region->_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 MAX(xLength, yLength);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::PathFinderStep() {
+ int i;
+ // get lowest unmarked
+ int lowest_dist = INT_MAX;
+ CAdPathPoint *lowest_pt = NULL;
+
+ for (i = 0; i < _pFPointsNum; i++)
+ if (!_pFPath[i]->_marked && _pFPath[i]->_distance < lowest_dist) {
+ lowest_dist = _pFPath[i]->_distance;
+ lowest_pt = _pFPath[i];
+ }
+
+ if (lowest_pt == NULL) { // no path -> terminate PathFinder
+ _pFReady = true;
+ _pFTargetPath->SetReady(true);
+ return;
+ }
+
+ lowest_pt->_marked = true;
+
+ // target point marked, generate path and terminate
+ if (lowest_pt->x == _pFTarget->x && lowest_pt->y == _pFTarget->y) {
+ while (lowest_pt != NULL) {
+ _pFTargetPath->_points.InsertAt(0, new CBPoint(lowest_pt->x, lowest_pt->y));
+ lowest_pt = lowest_pt->_origin;
+ }
+
+ _pFReady = true;
+ _pFTargetPath->SetReady(true);
+ return;
+ }
+
+ // otherwise keep on searching
+ for (i = 0; i < _pFPointsNum; i++)
+ if (!_pFPath[i]->_marked) {
+ int j = GetPointsDist(*lowest_pt, *_pFPath[i], _pFRequester);
+ if (j != -1 && lowest_pt->_distance + j < _pFPath[i]->_distance) {
+ _pFPath[i]->_distance = lowest_pt->_distance + j;
+ _pFPath[i]->_origin = lowest_pt;
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::InitLoop() {
+#ifdef _DEBUGxxxx
+ int nu_steps = 0;
+ uint32 start = Game->_currentTime;
+ while (!_pFReady && CBPlatform::GetTime() - start <= _pFMaxTime) {
+ PathFinderStep();
+ nu_steps++;
+ }
+ if (nu_steps > 0) Game->LOG(0, "STAT: PathFinder iterations in one loop: %d (%s) _pFMaxTime=%d", nu_steps, _pFReady ? "finished" : "not yet done", _pFMaxTime);
+#else
+ uint32 start = Game->_currentTime;
+ while (!_pFReady && CBPlatform::GetTime() - start <= _pFMaxTime) PathFinderStep();
+#endif
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdScene::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ delete[] _filename;
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_filename, Filename);
+
+ if (FAILED(ret = LoadBuffer(Buffer, true))) Game->LOG(0, "Error parsing SCENE file '%s'", Filename);
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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);
+ _layers.Add(layer);
+ if (layer->_main) {
+ _mainLayer = layer;
+ _width = layer->_width;
+ _height = layer->_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);
+ _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);
+ _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);
+ _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 _cursor;
+ _cursor = new CBSprite(Game);
+ if (!_cursor || FAILED(_cursor->LoadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_CAMERA:
+ strcpy(camera, (char *)params);
+ break;
+
+ case TOKEN_EDITOR_MARGIN_H:
+ parser.ScanStr((char *)params, "%d", &_editorMarginH);
+ break;
+
+ case TOKEN_EDITOR_MARGIN_V:
+ parser.ScanStr((char *)params, "%d", &_editorMarginV);
+ break;
+
+ case TOKEN_EDITOR_COLOR_FRAME:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ _editorColFrame = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_ENTITY:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ _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);
+ _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);
+ _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);
+ _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);
+ _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);
+ _editorColWaypointsSel = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_REGION:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ _editorColRegion = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_DECORATION:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ _editorColDecor = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_BLOCKED:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ _editorColBlocked = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_WAYPOINTS:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ _editorColWaypoints = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_COLOR_SCALE:
+ parser.ScanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa);
+ _editorColScale = DRGBA(ar, ag, ab, aa);
+ break;
+
+ case TOKEN_EDITOR_SHOW_REGIONS:
+ parser.ScanStr((char *)params, "%b", &_editorShowRegions);
+ break;
+
+ case TOKEN_EDITOR_SHOW_BLOCKED:
+ parser.ScanStr((char *)params, "%b", &_editorShowBlocked);
+ break;
+
+ case TOKEN_EDITOR_SHOW_DECORATION:
+ parser.ScanStr((char *)params, "%b", &_editorShowDecor);
+ break;
+
+ case TOKEN_EDITOR_SHOW_ENTITIES:
+ parser.ScanStr((char *)params, "%b", &_editorShowEntities);
+ break;
+
+ case TOKEN_EDITOR_SHOW_SCALE:
+ parser.ScanStr((char *)params, "%b", &_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 (!_viewport) _viewport = new CBViewport(Game);
+ if (_viewport) _viewport->SetRect(rc.left, rc.top, rc.right, rc.bottom, true);
+ }
+
+ case TOKEN_PERSISTENT_STATE:
+ parser.ScanStr((char *)params, "%b", &_persistentState);
+ break;
+
+ case TOKEN_PERSISTENT_STATE_SPRITES:
+ parser.ScanStr((char *)params, "%b", &_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 (_mainLayer == NULL) Game->LOG(0, "Warning: scene '%s' has no main layer.", _filename);
+
+
+ SortScaleLevels();
+ SortRotLevels();
+
+ _initialized = true;
+
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::TraverseNodes(bool Update) {
+ if (!_initialized) return S_OK;
+
+ int j, k;
+ CAdGame *AdGame = (CAdGame *)Game;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // prepare viewport
+ bool PopViewport = false;
+ if (_viewport && !Game->_editorMode) {
+ Game->PushViewport(_viewport);
+ PopViewport = true;
+ } else if (AdGame->_sceneViewport && !Game->_editorMode) {
+ Game->PushViewport(AdGame->_sceneViewport);
+ PopViewport = true;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // *** adjust scroll offset
+ if (Update) {
+ /*
+ if(_autoScroll && Game->_mainObject != NULL)
+ {
+ ScrollToObject(Game->_mainObject);
+ }
+ */
+
+ if (_autoScroll) {
+ // adjust horizontal scroll
+ if (Game->_timer - _lastTimeH >= _scrollTimeH) {
+ _lastTimeH = Game->_timer;
+ if (_offsetLeft < _targetOffsetLeft) {
+ _offsetLeft += _scrollPixelsH;
+ _offsetLeft = MIN(_offsetLeft, _targetOffsetLeft);
+ } else if (_offsetLeft > _targetOffsetLeft) {
+ _offsetLeft -= _scrollPixelsH;
+ _offsetLeft = MAX(_offsetLeft, _targetOffsetLeft);
+ }
+ }
+
+ // adjust vertical scroll
+ if (Game->_timer - _lastTimeV >= _scrollTimeV) {
+ _lastTimeV = Game->_timer;
+ if (_offsetTop < _targetOffsetTop) {
+ _offsetTop += _scrollPixelsV;
+ _offsetTop = MIN(_offsetTop, _targetOffsetTop);
+ } else if (_offsetTop > _targetOffsetTop) {
+ _offsetTop -= _scrollPixelsV;
+ _offsetTop = MAX(_offsetTop, _targetOffsetTop);
+ }
+ }
+
+ if (_offsetTop == _targetOffsetTop && _offsetLeft == _targetOffsetLeft) _ready = true;
+ } else _ready = true; // not scrolling, i.e. always ready
+ }
+
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ int ViewportX, ViewportY;
+ GetViewportOffset(&ViewportX, &ViewportY);
+
+ int ScrollableX = _width - ViewportWidth;
+ int ScrollableY = _height - ViewportHeight;
+
+ double WidthRatio = ScrollableX <= 0 ? 0 : ((double)(_offsetLeft) / (double)ScrollableX);
+ double HeightRatio = ScrollableY <= 0 ? 0 : ((double)(_offsetTop) / (double)ScrollableY);
+
+ int OrigX, OrigY;
+ Game->GetOffset(&OrigX, &OrigY);
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // *** display/update everything
+ Game->_renderer->Setup2D();
+
+ // for each layer
+ /* int MainOffsetX = 0; */
+ /* int MainOffsetY = 0; */
+
+ for (j = 0; j < _layers.GetSize(); j++) {
+ if (!_layers[j]->_active) continue;
+
+ // make layer exclusive
+ if (!Update) {
+ if (_layers[j]->_closeUp && !Game->_editorMode) {
+ if (!_shieldWindow) _shieldWindow = new CUIWindow(Game);
+ if (_shieldWindow) {
+ _shieldWindow->_posX = _shieldWindow->_posY = 0;
+ _shieldWindow->_width = Game->_renderer->_width;
+ _shieldWindow->_height = Game->_renderer->_height;
+ _shieldWindow->Display();
+ }
+ }
+ }
+
+ if (_paralaxScrolling) {
+ int OffsetX = (int)(WidthRatio * (_layers[j]->_width - ViewportWidth) - ViewportX);
+ int OffsetY = (int)(HeightRatio * (_layers[j]->_height - ViewportHeight) - ViewportY);
+ Game->SetOffset(OffsetX, OffsetY);
+
+ Game->_offsetPercentX = (float)OffsetX / ((float)_layers[j]->_width - ViewportWidth) * 100.0f;
+ Game->_offsetPercentY = (float)OffsetY / ((float)_layers[j]->_height - ViewportHeight) * 100.0f;
+
+ //Game->QuickMessageForm("%d %f", OffsetX+ViewportX, Game->_offsetPercentX);
+ } else {
+ Game->SetOffset(_offsetLeft - ViewportX, _offsetTop - ViewportY);
+
+ Game->_offsetPercentX = (float)(_offsetLeft - ViewportX) / ((float)_layers[j]->_width - ViewportWidth) * 100.0f;
+ Game->_offsetPercentY = (float)(_offsetTop - ViewportY) / ((float)_layers[j]->_height - ViewportHeight) * 100.0f;
+ }
+
+
+ // for each node
+ for (k = 0; k < _layers[j]->_nodes.GetSize(); k++) {
+ CAdSceneNode *Node = _layers[j]->_nodes[k];
+ switch (Node->_type) {
+ case OBJECT_ENTITY:
+ if (Node->_entity->_active && (Game->_editorMode || !Node->_entity->_editorOnly)) {
+ Game->_renderer->Setup2D();
+
+ if (Update) Node->_entity->Update();
+ else Node->_entity->Display();
+ }
+ break;
+
+ case OBJECT_REGION: {
+ if (Node->_region->_blocked) break;
+ if (Node->_region->_decoration) break;
+
+ if (!Update) DisplayRegionContent(Node->_region);
+ }
+ break;
+ default:
+ error("AdScene::TraverseNodes - Unhandled enum");
+ break;
+ } // switch
+ } // each node
+
+ // display/update all objects which are off-regions
+ if (_layers[j]->_main) {
+ if (Update) {
+ UpdateFreeObjects();
+ } else {
+ DisplayRegionContent(NULL);
+ }
+ }
+ } // each layer
+
+
+ // restore state
+ Game->SetOffset(OrigX, OrigY);
+ Game->_renderer->Setup2D();
+
+ // display/update fader
+ if (_fader) {
+ if (Update) _fader->Update();
+ else _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->_objects.GetSize(); i++) {
+ if (!AdGame->_objects[i]->_active) continue;
+
+ AdGame->_objects[i]->Update();
+ AdGame->_objects[i]->_drawn = false;
+ }
+
+
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (!_objects[i]->_active) continue;
+
+ _objects[i]->Update();
+ _objects[i]->_drawn = false;
+ }
+
+
+ if (_autoScroll && Game->_mainObject != NULL) {
+ ScrollToObject(Game->_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->_objects.GetSize(); i++) {
+ Obj = AdGame->_objects[i];
+ if (Obj->_active && !Obj->_drawn && (Obj->_stickRegion == Region || Region == NULL || (Obj->_stickRegion == NULL && Region->PointInRegion(Obj->_posX, Obj->_posY)))) {
+ Objects.Add(Obj);
+ }
+ }
+
+ // scene objects
+ for (i = 0; i < _objects.GetSize(); i++) {
+ Obj = _objects[i];
+ if (Obj->_active && !Obj->_editorOnly && !Obj->_drawn && (Obj->_stickRegion == Region || Region == NULL || (Obj->_stickRegion == NULL && Region->PointInRegion(Obj->_posX, Obj->_posY)))) {
+ Objects.Add(Obj);
+ }
+ }
+
+ // sort by _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->_is3D) continue;
+
+ Game->_renderer->Setup2D();
+
+ if (Game->_editorMode || !Obj->_editorOnly) Obj->Display();
+ Obj->_drawn = true;
+ }
+
+
+ // display design only objects
+ if (!Display3DOnly) {
+ if (Game->_editorMode && Region == NULL) {
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i]->_active && _objects[i]->_editorOnly) {
+ _objects[i]->Display();
+ _objects[i]->_drawn = true;
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+int CAdScene::CompareObjs(const void *Obj1, const void *Obj2) {
+ CAdObject *Object1 = *(CAdObject **)Obj1;
+ CAdObject *Object2 = *(CAdObject **)Obj2;
+
+ if (Object1->_posY < Object2->_posY) return -1;
+ else if (Object1->_posY > Object2->_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 _posY
+ do {
+ obj = NULL;
+ int minY = INT_MAX;
+
+ // global objects
+ for (i = 0; i < AdGame->_objects.GetSize(); i++) {
+ if (AdGame->_objects[i]->_active && !AdGame->_objects[i]->_drawn && AdGame->_objects[i]->_posY < minY && (AdGame->_objects[i]->_stickRegion == Region || Region == NULL || (AdGame->_objects[i]->_stickRegion == NULL && Region->PointInRegion(AdGame->_objects[i]->_posX, AdGame->_objects[i]->_posY)))) {
+ obj = AdGame->_objects[i];
+ minY = AdGame->_objects[i]->_posY;
+ }
+ }
+
+ // scene objects
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i]->_active && !_objects[i]->_editorOnly && !_objects[i]->_drawn && _objects[i]->_posY < minY && (_objects[i]->_stickRegion == Region || Region == NULL || (_objects[i]->_stickRegion == NULL && Region->PointInRegion(_objects[i]->_posX, _objects[i]->_posY)))) {
+ obj = _objects[i];
+ minY = _objects[i]->_posY;
+ }
+ }
+
+
+ if (obj != NULL) {
+ Game->_renderer->Setup2D();
+
+ if (Game->_editorMode || !obj->_editorOnly) obj->Display();
+ obj->_drawn = true;
+ }
+ } while (obj != NULL);
+
+
+ // design only objects
+ if (Game->_editorMode && Region == NULL) {
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i]->_active && _objects[i]->_editorOnly) {
+ _objects[i]->Display();
+ _objects[i]->_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 = _targetOffsetLeft;
+ int OrigOffsetTop = _targetOffsetTop;
+
+ _targetOffsetLeft = MAX(0, OffsetX - ViewportWidth / 2);
+ _targetOffsetLeft = MIN(_targetOffsetLeft, _width - ViewportWidth);
+
+ _targetOffsetTop = MAX(0, OffsetY - ViewportHeight / 2);
+ _targetOffsetTop = MIN(_targetOffsetTop, _height - ViewportHeight);
+
+
+ if (Game->_mainObject && Game->_mainObject->_is3D) {
+ if (abs(OrigOffsetLeft - _targetOffsetLeft) < 5) _targetOffsetLeft = OrigOffsetLeft;
+ if (abs(OrigOffsetTop - _targetOffsetTop) < 5) _targetOffsetTop = OrigOffsetTop;
+ //_targetOffsetTop = 0;
+ }
+
+ _ready = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::ScrollToObject(CBObject *Object) {
+ if (Object) ScrollTo(Object->_posX, Object->_posY - Object->GetHeight() / 2);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::SkipToObject(CBObject *Object) {
+ if (Object) SkipTo(Object->_posX, Object->_posY - Object->GetHeight() / 2);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::SkipTo(int OffsetX, int OffsetY) {
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ _offsetLeft = MAX(0, OffsetX - ViewportWidth / 2);
+ _offsetLeft = MIN(_offsetLeft, _width - ViewportWidth);
+
+ _offsetTop = MAX(0, OffsetY - ViewportHeight / 2);
+ _offsetTop = MIN(_offsetTop, _height - ViewportHeight);
+
+ _targetOffsetLeft = _offsetLeft;
+ _targetOffsetTop = _offsetTop;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const 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 >= _layers.GetSize()) Stack->PushNULL();
+ else Stack->PushNative(_layers[layer], true);
+ } else {
+ const char *LayerName = val->GetString();
+ bool LayerFound = false;
+ for (int i = 0; i < _layers.GetSize(); i++) {
+ if (scumm_stricmp(LayerName, _layers[i]->_name) == 0) {
+ Stack->PushNative(_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 >= _waypointGroups.GetSize()) Stack->PushNULL();
+ else Stack->PushNative(_waypointGroups[group], true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetNode
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetNode") == 0) {
+ Stack->CorrectParams(1);
+ const 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 < _objects.GetSize()) Ret = _objects[Index];
+ } else {
+ const char *Name = Val->GetString();
+ for (int i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i] && _objects[i]->_name && scumm_stricmp(_objects[i]->_name, Name) == 0) {
+ Ret = _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 (_mainLayer) {
+ for (int i = _mainLayer->_nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = _mainLayer->_nodes[i];
+ if (Node->_type == OBJECT_REGION && Node->_region->_active && Node->_region->PointInRegion(X, Y)) {
+ if (Node->_region->_decoration && !IncludeDecors) continue;
+
+ Stack->PushNative(Node->_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 (_autoScroll) {
+ if (_targetOffsetLeft != _offsetLeft || _targetOffsetTop != _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);
+
+ _fader->FadeOut(DRGBA(Red, Green, Blue, Alpha), Duration);
+ if (strcmp(Name, "FadeOutAsync") != 0) Script->WaitFor(_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);
+
+ _fader->FadeIn(DRGBA(Red, Green, Blue, Alpha), Duration);
+ if (strcmp(Name, "FadeInAsync") != 0) Script->WaitFor(_fader);
+
+ Stack->PushNULL();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetFadeColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetFadeColor") == 0) {
+ Stack->CorrectParams(0);
+ Stack->PushInt(_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->_renderer->_width;
+ if (Height <= 0) Height = Game->_renderer->_height;
+
+ if (!_viewport) _viewport = new CBViewport(Game);
+ if (_viewport) _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 (_mainLayer) {
+ Layer->_width = _mainLayer->_width;
+ Layer->_height = _mainLayer->_height;
+ }
+ _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 (_mainLayer) {
+ Layer->_width = _mainLayer->_width;
+ Layer->_height = _mainLayer->_height;
+ }
+ if (Index < 0) Index = 0;
+ if (Index <= _layers.GetSize() - 1) _layers.InsertAt(Index, Layer);
+ else _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 < _layers.GetSize(); i++) {
+ if (_layers[i] == Temp) {
+ ToDelete = _layers[i];
+ break;
+ }
+ }
+ } else {
+ int Index = Val->GetInt();
+ if (Index >= 0 && Index < _layers.GetSize()) {
+ ToDelete = _layers[Index];
+ }
+ }
+ if (ToDelete == NULL) {
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ if (ToDelete->_main) {
+ Script->RuntimeError("Scene.DeleteLayer - cannot delete main scene layer");
+ Stack->PushBool(false);
+ return S_OK;
+ }
+
+ for (int i = 0; i < _layers.GetSize(); i++) {
+ if (_layers[i] == ToDelete) {
+ _layers.RemoveAt(i);
+ Game->UnregisterObject(ToDelete);
+ break;
+ }
+ }
+ Stack->PushBool(true);
+ return S_OK;
+ }
+
+ else return CBObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdScene::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("scene");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumLayers (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumLayers") == 0) {
+ _scValue->SetInt(_layers.GetSize());
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumWaypointGroups (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumWaypointGroups") == 0) {
+ _scValue->SetInt(_waypointGroups.GetSize());
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MainLayer (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MainLayer") == 0) {
+ if (_mainLayer) _scValue->SetNative(_mainLayer, true);
+ else _scValue->SetNULL();
+
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumFreeNodes (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumFreeNodes") == 0) {
+ _scValue->SetInt(_objects.GetSize());
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MouseX (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MouseX") == 0) {
+ int ViewportX;
+ GetViewportOffset(&ViewportX);
+
+ _scValue->SetInt(Game->_mousePos.x + _offsetLeft - ViewportX);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MouseY (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MouseY") == 0) {
+ int ViewportY;
+ GetViewportOffset(NULL, &ViewportY);
+
+ _scValue->SetInt(Game->_mousePos.y + _offsetTop - ViewportY);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AutoScroll
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AutoScroll") == 0) {
+ _scValue->SetBool(_autoScroll);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentState
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentState") == 0) {
+ _scValue->SetBool(_persistentState);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentStateSprites
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentStateSprites") == 0) {
+ _scValue->SetBool(_persistentStateSprites);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsX") == 0) {
+ _scValue->SetInt(_scrollPixelsH);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsY") == 0) {
+ _scValue->SetInt(_scrollPixelsV);
+ return _scValue;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedX") == 0) {
+ _scValue->SetInt(_scrollTimeH);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedY") == 0) {
+ _scValue->SetInt(_scrollTimeV);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetX") == 0) {
+ _scValue->SetInt(_offsetLeft);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetY") == 0) {
+ _scValue->SetInt(_offsetTop);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Width (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ if (_mainLayer) _scValue->SetInt(_mainLayer->_width);
+ else _scValue->SetInt(0);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Height (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ if (_mainLayer) _scValue->SetInt(_mainLayer->_height);
+ else _scValue->SetInt(0);
+ return _scValue;
+ }
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::ScSetProperty(const char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Name") == 0) {
+ SetName(Value->GetString());
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AutoScroll
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AutoScroll") == 0) {
+ _autoScroll = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentState
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentState") == 0) {
+ _persistentState = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PersistentStateSprites
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "PersistentStateSprites") == 0) {
+ _persistentStateSprites = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsX") == 0) {
+ _scrollPixelsH = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollPixelsY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollPixelsY") == 0) {
+ _scrollPixelsV = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedX") == 0) {
+ _scrollTimeH = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ScrollSpeedY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScrollSpeedY") == 0) {
+ _scrollTimeV = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetX") == 0) {
+ _offsetLeft = Value->GetInt();
+
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ _offsetLeft = MAX(0, _offsetLeft - ViewportWidth / 2);
+ _offsetLeft = MIN(_offsetLeft, _width - ViewportWidth);
+ _targetOffsetLeft = _offsetLeft;
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // OffsetY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "OffsetY") == 0) {
+ _offsetTop = Value->GetInt();
+
+ int ViewportWidth, ViewportHeight;
+ GetViewportSize(&ViewportWidth, &ViewportHeight);
+
+ _offsetTop = MAX(0, _offsetTop - ViewportHeight / 2);
+ _offsetTop = MIN(_offsetTop, _height - ViewportHeight);
+ _targetOffsetTop = _offsetTop;
+
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CAdScene::ScToString() {
+ return "[scene object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::AddObject(CAdObject *Object) {
+ _objects.Add(Object);
+ return Game->RegisterObject(Object);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::RemoveObject(CAdObject *Object) {
+ for (int i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i] == Object) {
+ _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", _name);
+ Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption());
+
+ if (_persistentState)
+ Buffer->PutTextIndent(Indent + 2, "PERSISTENT_STATE=%s\n", _persistentState ? "TRUE" : "FALSE");
+
+ if (!_persistentStateSprites)
+ Buffer->PutTextIndent(Indent + 2, "PERSISTENT_STATE_SPRITES=%s\n", _persistentStateSprites ? "TRUE" : "FALSE");
+
+
+ // scripts
+ for (i = 0; i < _scripts.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // properties
+ if (_scProp) _scProp->SaveAsText(Buffer, Indent + 2);
+
+ // viewport
+ if (_viewport) {
+ RECT *rc = _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", _editorMarginH);
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_MARGIN_V=%d\n", _editorMarginV);
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_FRAME { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColFrame), D3DCOLGetG(_editorColFrame), D3DCOLGetB(_editorColFrame), D3DCOLGetA(_editorColFrame));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_ENTITY_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColEntitySel), D3DCOLGetG(_editorColEntitySel), D3DCOLGetB(_editorColEntitySel), D3DCOLGetA(_editorColEntitySel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_REGION_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColRegionSel), D3DCOLGetG(_editorColRegionSel), D3DCOLGetB(_editorColRegionSel), D3DCOLGetA(_editorColRegionSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_BLOCKED_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColBlockedSel), D3DCOLGetG(_editorColBlockedSel), D3DCOLGetB(_editorColBlockedSel), D3DCOLGetA(_editorColBlockedSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_DECORATION_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColDecorSel), D3DCOLGetG(_editorColDecorSel), D3DCOLGetB(_editorColDecorSel), D3DCOLGetA(_editorColDecorSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_WAYPOINTS_SEL { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColWaypointsSel), D3DCOLGetG(_editorColWaypointsSel), D3DCOLGetB(_editorColWaypointsSel), D3DCOLGetA(_editorColWaypointsSel));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_ENTITY { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColEntity), D3DCOLGetG(_editorColEntity), D3DCOLGetB(_editorColEntity), D3DCOLGetA(_editorColEntity));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_REGION { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColRegion), D3DCOLGetG(_editorColRegion), D3DCOLGetB(_editorColRegion), D3DCOLGetA(_editorColRegion));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_DECORATION { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColDecor), D3DCOLGetG(_editorColDecor), D3DCOLGetB(_editorColDecor), D3DCOLGetA(_editorColDecor));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_BLOCKED { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColBlocked), D3DCOLGetG(_editorColBlocked), D3DCOLGetB(_editorColBlocked), D3DCOLGetA(_editorColBlocked));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_WAYPOINTS { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColWaypoints), D3DCOLGetG(_editorColWaypoints), D3DCOLGetB(_editorColWaypoints), D3DCOLGetA(_editorColWaypoints));
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_COLOR_SCALE { %d,%d,%d,%d }\n", D3DCOLGetR(_editorColScale), D3DCOLGetG(_editorColScale), D3DCOLGetB(_editorColScale), D3DCOLGetA(_editorColScale));
+
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_REGIONS=%s\n", _editorShowRegions ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_BLOCKED=%s\n", _editorShowBlocked ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_DECORATION=%s\n", _editorShowDecor ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_ENTITIES=%s\n", _editorShowEntities ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SHOW_SCALE=%s\n", _editorShowScale ? "TRUE" : "FALSE");
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ // waypoints
+ Buffer->PutTextIndent(Indent + 2, "; ----- waypoints\n");
+ for (i = 0; i < _waypointGroups.GetSize(); i++) _waypointGroups[i]->SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // layers
+ Buffer->PutTextIndent(Indent + 2, "; ----- layers\n");
+ for (i = 0; i < _layers.GetSize(); i++) _layers[i]->SaveAsText(Buffer, Indent + 2);
+
+ // scale levels
+ Buffer->PutTextIndent(Indent + 2, "; ----- scale levels\n");
+ for (i = 0; i < _scaleLevels.GetSize(); i++) _scaleLevels[i]->SaveAsText(Buffer, Indent + 2);
+
+ // rotation levels
+ Buffer->PutTextIndent(Indent + 2, "; ----- rotation levels\n");
+ for (i = 0; i < _rotLevels.GetSize(); i++) _rotLevels[i]->SaveAsText(Buffer, Indent + 2);
+
+
+ Buffer->PutTextIndent(Indent + 2, "\n");
+
+ // free entities
+ Buffer->PutTextIndent(Indent + 2, "; ----- free entities\n");
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i]->_type == OBJECT_ENTITY) {
+ _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 < _scaleLevels.GetSize() - 1; i++) {
+ if (_scaleLevels[i]->_posY > _scaleLevels[i + 1]->_posY) {
+ CAdScaleLevel *sl = _scaleLevels[i];
+ _scaleLevels[i] = _scaleLevels[i + 1];
+ _scaleLevels[i + 1] = sl;
+
+ changed = true;
+ }
+ }
+
+ } while (changed);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::SortRotLevels() {
+ bool changed;
+ do {
+ changed = false;
+ for (int i = 0; i < _rotLevels.GetSize() - 1; i++) {
+ if (_rotLevels[i]->_posX > _rotLevels[i + 1]->_posX) {
+ CAdRotLevel *rl = _rotLevels[i];
+ _rotLevels[i] = _rotLevels[i + 1];
+ _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 < _scaleLevels.GetSize(); i++) {
+ CAdScaleLevel *xxx = _scaleLevels[i];
+ int j = _scaleLevels.GetSize();
+ if (_scaleLevels[i]->_posY < Y) prev = _scaleLevels[i];
+ else {
+ next = _scaleLevels[i];
+ break;
+ }
+ }
+
+ if (prev == NULL || next == NULL) return 100;
+
+ int delta_y = next->_posY - prev->_posY;
+ float delta_scale = next->_scale - prev->_scale;
+ Y -= prev->_posY;
+
+ float percent = (float)Y / ((float)delta_y / 100.0f);
+ return prev->_scale + delta_scale / 100 * percent;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_autoScroll));
+ PersistMgr->Transfer(TMEMBER(_editorColBlocked));
+ PersistMgr->Transfer(TMEMBER(_editorColBlockedSel));
+ PersistMgr->Transfer(TMEMBER(_editorColDecor));
+ PersistMgr->Transfer(TMEMBER(_editorColDecorSel));
+ PersistMgr->Transfer(TMEMBER(_editorColEntity));
+ PersistMgr->Transfer(TMEMBER(_editorColEntitySel));
+ PersistMgr->Transfer(TMEMBER(_editorColFrame));
+ PersistMgr->Transfer(TMEMBER(_editorColRegion));
+ PersistMgr->Transfer(TMEMBER(_editorColRegionSel));
+ PersistMgr->Transfer(TMEMBER(_editorColScale));
+ PersistMgr->Transfer(TMEMBER(_editorColWaypoints));
+ PersistMgr->Transfer(TMEMBER(_editorColWaypointsSel));
+ PersistMgr->Transfer(TMEMBER(_editorMarginH));
+ PersistMgr->Transfer(TMEMBER(_editorMarginV));
+ PersistMgr->Transfer(TMEMBER(_editorShowBlocked));
+ PersistMgr->Transfer(TMEMBER(_editorShowDecor));
+ PersistMgr->Transfer(TMEMBER(_editorShowEntities));
+ PersistMgr->Transfer(TMEMBER(_editorShowRegions));
+ PersistMgr->Transfer(TMEMBER(_editorShowScale));
+ PersistMgr->Transfer(TMEMBER(_fader));
+ PersistMgr->Transfer(TMEMBER(_height));
+ PersistMgr->Transfer(TMEMBER(_initialized));
+ PersistMgr->Transfer(TMEMBER(_lastTimeH));
+ PersistMgr->Transfer(TMEMBER(_lastTimeV));
+ _layers.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_mainLayer));
+ _objects.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_offsetLeft));
+ PersistMgr->Transfer(TMEMBER(_offsetTop));
+ PersistMgr->Transfer(TMEMBER(_paralaxScrolling));
+ PersistMgr->Transfer(TMEMBER(_persistentState));
+ PersistMgr->Transfer(TMEMBER(_persistentStateSprites));
+ PersistMgr->Transfer(TMEMBER(_pFMaxTime));
+ _pFPath.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_pFPointsNum));
+ PersistMgr->Transfer(TMEMBER(_pFReady));
+ PersistMgr->Transfer(TMEMBER(_pFRequester));
+ PersistMgr->Transfer(TMEMBER(_pFTarget));
+ PersistMgr->Transfer(TMEMBER(_pFTargetPath));
+ _rotLevels.Persist(PersistMgr);
+ _scaleLevels.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_scrollPixelsH));
+ PersistMgr->Transfer(TMEMBER(_scrollPixelsV));
+ PersistMgr->Transfer(TMEMBER(_scrollTimeH));
+ PersistMgr->Transfer(TMEMBER(_scrollTimeV));
+ PersistMgr->Transfer(TMEMBER(_shieldWindow));
+ PersistMgr->Transfer(TMEMBER(_targetOffsetLeft));
+ PersistMgr->Transfer(TMEMBER(_targetOffsetTop));
+ _waypointGroups.Persist(PersistMgr);
+ PersistMgr->Transfer(TMEMBER(_viewport));
+ PersistMgr->Transfer(TMEMBER(_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) || !_mainLayer) {
+ return S_OK;
+ }
+
+ // right
+ int length_right = 0;
+ bool found_right = false;
+ for (x = *X, y = *Y; x < _mainLayer->_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 < _mainLayer->_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() {
+ _pFPointsNum = 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdScene::PFPointsAdd(int X, int Y, int Distance) {
+ if (_pFPointsNum >= _pFPath.GetSize()) {
+ _pFPath.Add(new CAdPathPoint(X, Y, Distance));
+ } else {
+ _pFPath[_pFPointsNum]->x = X;
+ _pFPath[_pFPointsNum]->y = Y;
+ _pFPath[_pFPointsNum]->_distance = Distance;
+ _pFPath[_pFPointsNum]->_marked = false;
+ _pFPath[_pFPointsNum]->_origin = NULL;
+ }
+
+ _pFPointsNum++;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::GetViewportOffset(int *OffsetX, int *OffsetY) {
+ CAdGame *AdGame = (CAdGame *)Game;
+ if (_viewport && !Game->_editorMode) {
+ if (OffsetX) *OffsetX = _viewport->_offsetX;
+ if (OffsetY) *OffsetY = _viewport->_offsetY;
+ } else if (AdGame->_sceneViewport && !Game->_editorMode) {
+ if (OffsetX) *OffsetX = AdGame->_sceneViewport->_offsetX;
+ if (OffsetY) *OffsetY = AdGame->_sceneViewport->_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 (_viewport && !Game->_editorMode) {
+ if (Width) *Width = _viewport->GetWidth();
+ if (Height) *Height = _viewport->GetHeight();
+ } else if (AdGame->_sceneViewport && !Game->_editorMode) {
+ if (Width) *Width = AdGame->_sceneViewport->GetWidth();
+ if (Height) *Height = AdGame->_sceneViewport->GetHeight();
+ } else {
+ if (Width) *Width = Game->_renderer->_width;
+ if (Height) *Height = Game->_renderer->_height;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdScene::GetOffsetLeft() {
+ int ViewportX;
+ GetViewportOffset(&ViewportX);
+
+ return _offsetLeft - ViewportX;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CAdScene::GetOffsetTop() {
+ int ViewportY;
+ GetViewportOffset(NULL, &ViewportY);
+
+ return _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) {
+ _offsetLeft = OffsetLeft;
+ _offsetTop = OffsetTop;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBObject *CAdScene::GetNodeByName(const char *Name) {
+ int i;
+ CBObject *ret = NULL;
+
+ // dependent objects
+ for (i = 0; i < _layers.GetSize(); i++) {
+ CAdLayer *layer = _layers[i];
+ for (int j = 0; j < layer->_nodes.GetSize(); j++) {
+ CAdSceneNode *node = layer->_nodes[j];
+ if ((node->_type == OBJECT_ENTITY && !scumm_stricmp(Name, node->_entity->_name)) ||
+ (node->_type == OBJECT_REGION && !scumm_stricmp(Name, node->_region->_name))) {
+ switch (node->_type) {
+ case OBJECT_ENTITY:
+ ret = node->_entity;
+ break;
+ case OBJECT_REGION:
+ ret = node->_region;
+ break;
+ default:
+ ret = NULL;
+ }
+ return ret;
+ }
+ }
+ }
+
+ // free entities
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i]->_type == OBJECT_ENTITY && !scumm_stricmp(Name, _objects[i]->_name)) {
+ return _objects[i];
+ }
+ }
+
+ // waypoint groups
+ for (i = 0; i < _waypointGroups.GetSize(); i++) {
+ if (!scumm_stricmp(Name, _waypointGroups[i]->_name)) {
+ return _waypointGroups[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::SaveState() {
+ return PersistState(true);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::LoadState() {
+ return PersistState(false);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::PersistState(bool Saving) {
+ if (!_persistentState) return S_OK;
+
+ CAdGame *AdGame = (CAdGame *)Game;
+ CAdSceneState *State = AdGame->GetSceneState(_filename, Saving);
+ if (!State) return S_OK;
+
+
+ int i;
+ CAdNodeState *NodeState;
+
+ // dependent objects
+ for (i = 0; i < _layers.GetSize(); i++) {
+ CAdLayer *layer = _layers[i];
+ for (int j = 0; j < layer->_nodes.GetSize(); j++) {
+ CAdSceneNode *node = layer->_nodes[j];
+ switch (node->_type) {
+ case OBJECT_ENTITY:
+ if (!node->_entity->_saveState) continue;
+ NodeState = State->GetNodeState(node->_entity->_name, Saving);
+ if (NodeState) {
+ NodeState->TransferEntity(node->_entity, _persistentStateSprites, Saving);
+ //if(Saving) NodeState->_active = node->_entity->_active;
+ //else node->_entity->_active = NodeState->_active;
+ }
+ break;
+ case OBJECT_REGION:
+ if (!node->_region->_saveState) continue;
+ NodeState = State->GetNodeState(node->_region->_name, Saving);
+ if (NodeState) {
+ if (Saving) NodeState->_active = node->_region->_active;
+ else node->_region->_active = NodeState->_active;
+ }
+ break;
+ }
+ }
+ }
+
+ // free entities
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (!_objects[i]->_saveState) continue;
+ if (_objects[i]->_type == OBJECT_ENTITY) {
+ NodeState = State->GetNodeState(_objects[i]->_name, Saving);
+ if (NodeState) {
+ NodeState->TransferEntity((CAdEntity *)_objects[i], _persistentStateSprites, Saving);
+ //if(Saving) NodeState->_active = _objects[i]->_active;
+ //else _objects[i]->_active = NodeState->_active;
+ }
+ }
+ }
+
+ // waypoint groups
+ for (i = 0; i < _waypointGroups.GetSize(); i++) {
+ NodeState = State->GetNodeState(_waypointGroups[i]->_name, Saving);
+ if (NodeState) {
+ if (Saving) NodeState->_active = _waypointGroups[i]->_active;
+ else _waypointGroups[i]->_active = NodeState->_active;
+ }
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+float CAdScene::GetRotationAt(int X, int Y) {
+ CAdRotLevel *prev = NULL;
+ CAdRotLevel *next = NULL;
+
+ for (int i = 0; i < _rotLevels.GetSize(); i++) {
+ CAdRotLevel *xxx = _rotLevels[i];
+ int j = _rotLevels.GetSize();
+ if (_rotLevels[i]->_posX < X) prev = _rotLevels[i];
+ else {
+ next = _rotLevels[i];
+ break;
+ }
+ }
+
+ if (prev == NULL || next == NULL) return 0;
+
+ int delta_x = next->_posX - prev->_posX;
+ float delta_rot = next->_rotation - prev->_rotation;
+ X -= prev->_posX;
+
+ float percent = (float)X / ((float)delta_x / 100.0f);
+ return prev->_rotation + delta_rot / 100 * percent;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::HandleItemAssociations(const char *ItemName, bool Show) {
+ int i;
+
+ for (i = 0; i < _layers.GetSize(); i++) {
+ CAdLayer *Layer = _layers[i];
+ for (int j = 0; j < Layer->_nodes.GetSize(); j++) {
+ if (Layer->_nodes[j]->_type == OBJECT_ENTITY) {
+ CAdEntity *Ent = Layer->_nodes[j]->_entity;
+
+ if (Ent->_item && strcmp(Ent->_item, ItemName) == 0) Ent->_active = Show;
+ }
+ }
+ }
+
+ for (i = 0; i < _objects.GetSize(); i++) {
+ if (_objects[i]->_type == OBJECT_ENTITY) {
+ CAdEntity *Ent = (CAdEntity *)_objects[i];
+ if (Ent->_item && strcmp(Ent->_item, ItemName) == 0) Ent->_active = Show;
+ }
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdScene::GetRegionsAt(int X, int Y, CAdRegion **RegionList, int NumRegions) {
+ int i;
+ int NumUsed = 0;
+ if (_mainLayer) {
+ for (i = _mainLayer->_nodes.GetSize() - 1; i >= 0; i--) {
+ CAdSceneNode *Node = _mainLayer->_nodes[i];
+ if (Node->_type == OBJECT_REGION && Node->_region->_active && Node->_region->PointInRegion(X, Y)) {
+ if (NumUsed < NumRegions - 1) {
+ RegionList[NumUsed] = Node->_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 < _layers.GetSize(); i++) {
+ // close-up layer -> remove everything below it
+ if (InteractiveOnly && _layers[i]->_closeUp) Objects.RemoveAll();
+
+
+ for (int j = 0; j < _layers[i]->_nodes.GetSize(); j++) {
+ CAdSceneNode *Node = _layers[i]->_nodes[j];
+ switch (Node->_type) {
+ case OBJECT_ENTITY: {
+ CAdEntity *Ent = Node->_entity;
+ if (Ent->_active && (Ent->_registrable || !InteractiveOnly))
+ Objects.Add(Ent);
+ }
+ break;
+
+ case OBJECT_REGION: {
+ CBArray<CAdObject *, CAdObject *> RegionObj;
+ GetRegionObjects(Node->_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->_objects.GetSize(); i++) {
+ Obj = AdGame->_objects[i];
+ if (Obj->_active && (Obj->_stickRegion == Region || Region == NULL || (Obj->_stickRegion == NULL && Region->PointInRegion(Obj->_posX, Obj->_posY)))) {
+ if (InteractiveOnly && !Obj->_registrable) continue;
+
+ Objects.Add(Obj);
+ }
+ }
+
+ // scene objects
+ for (i = 0; i < _objects.GetSize(); i++) {
+ Obj = _objects[i];
+ if (Obj->_active && !Obj->_editorOnly && (Obj->_stickRegion == Region || Region == NULL || (Obj->_stickRegion == NULL && Region->PointInRegion(Obj->_posX, Obj->_posY)))) {
+ if (InteractiveOnly && !Obj->_registrable) continue;
+
+ Objects.Add(Obj);
+ }
+ }
+
+ // sort by _posY
+ qsort(Objects.GetData(), Objects.GetSize(), sizeof(CAdObject *), CAdScene::CompareObjs);
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdScene.h b/engines/wintermute/Ad/AdScene.h
new file mode 100644
index 0000000000..87bd290970
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADSCENE_H
+#define WINTERMUTE_ADSCENE_H
+
+#include "engines/wintermute/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(const char *ItemName, bool Show);
+ CUIWindow *_shieldWindow;
+ float GetRotationAt(int X, int Y);
+ HRESULT LoadState();
+ HRESULT SaveState();
+ bool _persistentState;
+ bool _persistentStateSprites;
+ CBObject *GetNodeByName(const 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 *_viewport;
+ CBFader *_fader;
+ int _pFPointsNum;
+ void PFPointsAdd(int X, int Y, int Distance);
+ void PFPointsStart();
+ bool _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 _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 _autoScroll;
+ int _targetOffsetTop;
+ int _targetOffsetLeft;
+
+ int _scrollPixelsV;
+ uint32 _scrollTimeV;
+ uint32 _lastTimeV;
+
+ int _scrollPixelsH;
+ uint32 _scrollTimeH;
+ uint32 _lastTimeH;
+
+ virtual HRESULT Display();
+ uint32 _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 *_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 *> _layers;
+ CBArray<CAdObject *, CAdObject *> _objects;
+ CBArray<CAdWaypointGroup *, CAdWaypointGroup *> _waypointGroups;
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ int _width;
+ int _height;
+ HRESULT AddObject(CAdObject *Object);
+ HRESULT RemoveObject(CAdObject *Object);
+ int _editorMarginH;
+ int _editorMarginV;
+ uint32 _editorColFrame;
+ uint32 _editorColEntity;
+ uint32 _editorColRegion;
+ uint32 _editorColBlocked;
+ uint32 _editorColWaypoints;
+ uint32 _editorColEntitySel;
+ uint32 _editorColRegionSel;
+ uint32 _editorColBlockedSel;
+ uint32 _editorColWaypointsSel;
+ uint32 _editorColScale;
+ uint32 _editorColDecor;
+ uint32 _editorColDecorSel;
+
+ bool _editorShowRegions;
+ bool _editorShowBlocked;
+ bool _editorShowDecor;
+ bool _editorShowEntities;
+ bool _editorShowScale;
+ CBArray<CAdScaleLevel *, CAdScaleLevel *> _scaleLevels;
+ CBArray<CAdRotLevel *, CAdRotLevel *> _rotLevels;
+
+ virtual HRESULT RestoreDeviceObjects();
+ int GetPointsDist(CBPoint p1, CBPoint p2, CBObject *requester = NULL);
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+
+
+private:
+ HRESULT PersistState(bool Saving = true);
+ void PFAddWaypointGroup(CAdWaypointGroup *Wpt, CBObject *Requester = NULL);
+ bool _pFReady;
+ CBPoint *_pFTarget;
+ CAdPath *_pFTargetPath;
+ CBObject *_pFRequester;
+ CBArray<CAdPathPoint *, CAdPathPoint *> _pFPath;
+
+ int _offsetTop;
+ int _offsetLeft;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdSceneNode.cpp b/engines/wintermute/Ad/AdSceneNode.cpp
new file mode 100644
index 0000000000..d7d0ae98cc
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdSceneNode.h"
+#include "engines/wintermute/BGame.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSceneNode, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneNode::CAdSceneNode(CBGame *inGame): CBObject(inGame) {
+ _type = OBJECT_NONE;
+ _region = NULL;
+ _entity = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneNode::~CAdSceneNode() {
+ Game->UnregisterObject(_region);
+ _region = NULL;
+
+ Game->UnregisterObject(_entity);
+ _entity = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneNode::SetEntity(CAdEntity *Entity) {
+ _type = OBJECT_ENTITY;
+ _entity = Entity;
+ return Game->RegisterObject(Entity);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneNode::SetRegion(CAdRegion *Region) {
+ _type = OBJECT_REGION;
+ _region = Region;
+ return Game->RegisterObject(Region);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneNode::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_entity));
+ PersistMgr->Transfer(TMEMBER(_region));
+ PersistMgr->Transfer(TMEMBER_INT(_type));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdSceneNode.h b/engines/wintermute/Ad/AdSceneNode.h
new file mode 100644
index 0000000000..f6cc121fbc
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADSCENENODE_H
+#define WINTERMUTE_ADSCENENODE_H
+
+
+#include "engines/wintermute/Ad/AdTypes.h" // Added by ClassView
+#include "engines/wintermute/Ad/AdRegion.h" // Added by ClassView
+#include "engines/wintermute/Ad/AdEntity.h"
+
+namespace WinterMute {
+
+class CAdSceneNode : public CBObject {
+public:
+ DECLARE_PERSISTENT(CAdSceneNode, CBObject)
+ HRESULT SetRegion(CAdRegion *Region);
+ HRESULT SetEntity(CAdEntity *Entity);
+ CAdEntity *_entity;
+ CAdRegion *_region;
+ TObjectType _type;
+ CAdSceneNode(CBGame *inGame);
+ virtual ~CAdSceneNode();
+
+};
+
+}
+
+#endif
diff --git a/engines/wintermute/Ad/AdSceneState.cpp b/engines/wintermute/Ad/AdSceneState.cpp
new file mode 100644
index 0000000000..3a083498fe
--- /dev/null
+++ b/engines/wintermute/Ad/AdSceneState.cpp
@@ -0,0 +1,88 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/Ad/AdSceneState.h"
+#include "engines/wintermute/Ad/AdNodeState.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSceneState, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneState::CAdSceneState(CBGame *inGame): CBBase(inGame) {
+ _filename = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSceneState::~CAdSceneState() {
+ delete[] _filename;
+ _filename = NULL;
+
+ for (int i = 0; i < _nodeStates.GetSize(); i++) delete _nodeStates[i];
+ _nodeStates.RemoveAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSceneState::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(_filename));
+ _nodeStates.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSceneState::SetFilename(const char *Filename) {
+ delete[] _filename;
+ _filename = new char [strlen(Filename) + 1];
+ if (_filename) strcpy(_filename, Filename);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdNodeState *CAdSceneState::GetNodeState(char *Name, bool Saving) {
+ for (int i = 0; i < _nodeStates.GetSize(); i++) {
+ if (scumm_stricmp(_nodeStates[i]->_name, Name) == 0) return _nodeStates[i];
+ }
+
+ if (Saving) {
+ CAdNodeState *ret = new CAdNodeState(Game);
+ ret->SetName(Name);
+ _nodeStates.Add(ret);
+
+ return ret;
+ } else return NULL;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdSceneState.h b/engines/wintermute/Ad/AdSceneState.h
new file mode 100644
index 0000000000..264106b599
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADSCENESTATE_H
+#define WINTERMUTE_ADSCENESTATE_H
+
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/BBase.h"
+#include "engines/wintermute/coll_templ.h"
+
+namespace WinterMute {
+class CAdNodeState;
+class CAdSceneState : public CBBase {
+public:
+ CAdNodeState *GetNodeState(char *Name, bool Saving);
+ void SetFilename(const char *Filename);
+ DECLARE_PERSISTENT(CAdSceneState, CBBase)
+ CAdSceneState(CBGame *inGame);
+ virtual ~CAdSceneState();
+ char *_filename;
+ CBArray<CAdNodeState *, CAdNodeState *> _nodeStates;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdSentence.cpp b/engines/wintermute/Ad/AdSentence.cpp
new file mode 100644
index 0000000000..2395a4996c
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdSentence.h"
+#include "engines/wintermute/Ad/AdTalkDef.h"
+#include "engines/wintermute/Ad/AdTalkNode.h"
+#include "engines/wintermute/Ad/AdGame.h"
+#include "engines/wintermute/PathUtil.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BSound.h"
+#include "engines/wintermute/Ad/AdScene.h"
+#include "engines/wintermute/BFont.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSentence, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSentence::CAdSentence(CBGame *inGame): CBBase(inGame) {
+ _text = NULL;
+ _stances = NULL;
+ _tempStance = NULL;
+
+ _duration = 0;
+ _startTime = 0;
+ _currentStance = 0;
+
+ _font = NULL;
+
+ _pos.x = _pos.y = 0;
+ _width = Game->_renderer->_width;
+
+ _align = (TTextAlign)TAL_CENTER;
+
+ _sound = NULL;
+ _soundStarted = false;
+
+ _talkDef = NULL;
+ _currentSprite = NULL;
+ _currentSkelAnim = NULL;
+ _fixedPos = false;
+ _freezable = true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSentence::~CAdSentence() {
+ delete _sound;
+ delete[] _text;
+ delete[] _stances;
+ delete[] _tempStance;
+ delete _talkDef;
+ _sound = NULL;
+ _text = NULL;
+ _stances = NULL;
+ _tempStance = NULL;
+ _talkDef = NULL;
+
+ _currentSprite = NULL; // ref only
+ _currentSkelAnim = NULL;
+ _font = NULL; // ref only
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSentence::SetText(const char *Text) {
+ if (_text) delete [] _text;
+ _text = new char[strlen(Text) + 1];
+ if (_text) strcpy(_text, Text);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSentence::SetStances(const char *Stances) {
+ if (_stances) delete [] _stances;
+ if (Stances) {
+ _stances = new char[strlen(Stances) + 1];
+ if (_stances) strcpy(_stances, Stances);
+ } else _stances = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdSentence::GetCurrentStance() {
+ return GetStance(_currentStance);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdSentence::GetNextStance() {
+ _currentStance++;
+ return GetStance(_currentStance);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CAdSentence::GetStance(int Stance) {
+ if (_stances == NULL) return NULL;
+
+ if (_tempStance) delete [] _tempStance;
+ _tempStance = NULL;
+
+ char *start;
+ char *curr;
+ int pos;
+
+ if (Stance == 0) start = _stances;
+ else {
+ pos = 0;
+ start = NULL;
+ curr = _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--;
+
+ _tempStance = new char [curr - start + 1];
+ if (_tempStance) {
+ _tempStance[curr - start] = '\0';
+ strncpy(_tempStance, start, curr - start);
+ }
+
+ return _tempStance;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Display() {
+ if (!_font || !_text) return E_FAIL;
+
+ if (_sound && !_soundStarted) {
+ _sound->Play();
+ _soundStarted = true;
+ }
+
+ if (Game->_subtitles) {
+ int x = _pos.x;
+ int y = _pos.y;
+
+ if (!_fixedPos) {
+ x = x - ((CAdGame *)Game)->_scene->GetOffsetLeft();
+ y = y - ((CAdGame *)Game)->_scene->GetOffsetTop();
+ }
+
+
+ x = MAX(x, 0);
+ x = MIN(x, Game->_renderer->_width - _width);
+ y = MAX(y, 0);
+
+ _font->DrawText((byte *)_text, x, y, _width, _align);
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdSentence::SetSound(CBSound *Sound) {
+ if (!Sound) return;
+ delete _sound;
+ _sound = Sound;
+ _soundStarted = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Finish() {
+ if (_sound) _sound->Stop();
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Persist(CBPersistMgr *PersistMgr) {
+
+ PersistMgr->Transfer(TMEMBER(Game));
+
+ PersistMgr->Transfer(TMEMBER_INT(_align));
+ PersistMgr->Transfer(TMEMBER(_currentStance));
+ PersistMgr->Transfer(TMEMBER(_currentSprite));
+ PersistMgr->Transfer(TMEMBER(_currentSkelAnim));
+ PersistMgr->Transfer(TMEMBER(_duration));
+ PersistMgr->Transfer(TMEMBER(_font));
+ PersistMgr->Transfer(TMEMBER(_pos));
+ PersistMgr->Transfer(TMEMBER(_sound));
+ PersistMgr->Transfer(TMEMBER(_soundStarted));
+ PersistMgr->Transfer(TMEMBER(_stances));
+ PersistMgr->Transfer(TMEMBER(_startTime));
+ PersistMgr->Transfer(TMEMBER(_talkDef));
+ PersistMgr->Transfer(TMEMBER(_tempStance));
+ PersistMgr->Transfer(TMEMBER(_text));
+ PersistMgr->Transfer(TMEMBER(_width));
+ PersistMgr->Transfer(TMEMBER(_fixedPos));
+ PersistMgr->Transfer(TMEMBER(_freezable));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::SetupTalkFile(const char *SoundFilename) {
+ delete _talkDef;
+ _talkDef = NULL;
+ _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->_fileManager->OpenFile(talkDefFileName.c_str());
+ if (file) {
+ Game->_fileManager->CloseFile(file);
+ } else return S_OK; // no talk def file found
+
+
+ _talkDef = new CAdTalkDef(Game);
+ if (!_talkDef || FAILED(_talkDef->LoadFile(talkDefFileName.c_str()))) {
+ delete _talkDef;
+ _talkDef = NULL;
+ return E_FAIL;
+ }
+ //Game->LOG(0, "Using .talk file: %s", TalkDefFile);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSentence::Update(TDirection Dir) {
+ if (!_talkDef) return S_OK;
+
+ uint32 CurrentTime;
+ // if sound is available, synchronize with sound, otherwise use timer
+
+ /*
+ if(_sound) CurrentTime = _sound->GetPositionTime();
+ else CurrentTime = Game->_timer - _startTime;
+ */
+ CurrentTime = Game->_timer - _startTime;
+
+ bool TalkNodeFound = false;
+ for (int i = 0; i < _talkDef->_nodes.GetSize(); i++) {
+ if (_talkDef->_nodes[i]->IsInTimeInterval(CurrentTime, Dir)) {
+ TalkNodeFound = true;
+
+ CBSprite *NewSprite = _talkDef->_nodes[i]->GetSprite(Dir);
+ if (NewSprite != _currentSprite) NewSprite->Reset();
+ _currentSprite = NewSprite;
+
+ if (!_talkDef->_nodes[i]->_playToEnd) break;
+ }
+ }
+
+
+ // no talk node, try to use default sprite instead (if any)
+ if (!TalkNodeFound) {
+ CBSprite *NewSprite = _talkDef->GetDefaultSprite(Dir);
+ if (NewSprite) {
+ if (NewSprite != _currentSprite) NewSprite->Reset();
+ _currentSprite = NewSprite;
+ } else _currentSprite = NULL;
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdSentence::CanSkip() {
+ // prevent accidental sentence skipping (TODO make configurable)
+ return (Game->_timer - _startTime) > 300;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdSentence.h b/engines/wintermute/Ad/AdSentence.h
new file mode 100644
index 0000000000..495edceee0
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADSENTENCE_H
+#define WINTERMUTE_ADSENTENCE_H
+
+
+#include "engines/wintermute/BBase.h"
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/dctypes.h" // Added by ClassView
+
+namespace WinterMute {
+class CAdTalkDef;
+class CBFont;
+class CBSprite;
+class CBSound;
+class CAdSentence : public CBBase {
+public:
+ bool _freezable;
+ bool _fixedPos;
+ CBSprite *_currentSprite;
+ char *_currentSkelAnim;
+ HRESULT Update(TDirection Dir = DI_DOWN);
+ HRESULT SetupTalkFile(const char *SoundFilename);
+ DECLARE_PERSISTENT(CAdSentence, CBBase)
+ HRESULT Finish();
+ void SetSound(CBSound *Sound);
+ bool _soundStarted;
+ CBSound *_sound;
+ TTextAlign _align;
+ HRESULT Display();
+ int _width;
+ POINT _pos;
+ CBFont *_font;
+ char *GetNextStance();
+ char *GetCurrentStance();
+ void SetStances(const char *Stances);
+ void SetText(const char *Text);
+ int _currentStance;
+ uint32 _startTime;
+ char *_stances;
+ char *_text;
+ uint32 _duration;
+ CAdSentence(CBGame *inGame);
+ virtual ~CAdSentence();
+ CAdTalkDef *_talkDef;
+
+ bool CanSkip();
+
+private:
+ char *_tempStance;
+ char *GetStance(int Stance);
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdSpriteSet.cpp b/engines/wintermute/Ad/AdSpriteSet.cpp
new file mode 100644
index 0000000000..8ea4849e1c
--- /dev/null
+++ b/engines/wintermute/Ad/AdSpriteSet.cpp
@@ -0,0 +1,313 @@
+/* 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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdSpriteSet.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BFileManager.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdSpriteSet, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdSpriteSet::CAdSpriteSet(CBGame *inGame, CBObject *Owner): CBObject(inGame) {
+ _owner = Owner;
+
+ for (int i = 0; i < NUM_DIRECTIONS; i++)
+ _sprites[i] = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdSpriteSet::~CAdSpriteSet() {
+ for (int i = 0; i < NUM_DIRECTIONS; i++) {
+ delete _sprites[i];
+ _sprites[i] = NULL;
+ }
+
+ _owner = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSpriteSet::LoadFile(const char *Filename, int LifeTime, TSpriteCacheType CacheType) {
+ byte *Buffer = Game->_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 _sprites[DI_LEFT];
+ _sprites[DI_LEFT] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _sprites[DI_LEFT] = spr;
+ break;
+
+ case TOKEN_RIGHT:
+ delete _sprites[DI_RIGHT];
+ _sprites[DI_RIGHT] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _sprites[DI_RIGHT] = spr;
+ break;
+
+ case TOKEN_UP:
+ delete _sprites[DI_UP];
+ _sprites[DI_UP] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _sprites[DI_UP] = spr;
+ break;
+
+ case TOKEN_DOWN:
+ delete _sprites[DI_DOWN];
+ _sprites[DI_DOWN] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _sprites[DI_DOWN] = spr;
+ break;
+
+ case TOKEN_UP_LEFT:
+ delete _sprites[DI_UPLEFT];
+ _sprites[DI_UPLEFT] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _sprites[DI_UPLEFT] = spr;
+ break;
+
+ case TOKEN_UP_RIGHT:
+ delete _sprites[DI_UPRIGHT];
+ _sprites[DI_UPRIGHT] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _sprites[DI_UPRIGHT] = spr;
+ break;
+
+ case TOKEN_DOWN_LEFT:
+ delete _sprites[DI_DOWNLEFT];
+ _sprites[DI_DOWNLEFT] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _sprites[DI_DOWNLEFT] = spr;
+ break;
+
+ case TOKEN_DOWN_RIGHT:
+ delete _sprites[DI_DOWNRIGHT];
+ _sprites[DI_DOWNRIGHT] = NULL;
+ spr = new CBSprite(Game, _owner);
+ if (!spr || FAILED(spr->LoadFile((char *)params, LifeTime, CacheType))) cmd = PARSERR_GENERIC;
+ else _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(_owner));
+ for (int i = 0; i < NUM_DIRECTIONS; i++) {
+ PersistMgr->Transfer("", &_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 (_sprites[i] != NULL) {
+ ret = _sprites[i];
+ NumSteps = Dir - i;
+ break;
+ }
+ }
+
+ for (i = Dir; i < NUM_DIRECTIONS; i++) {
+ if (_sprites[i] != NULL) {
+ if (ret == NULL || NumSteps > i - Dir) return _sprites[i];
+ else return ret;
+ }
+ }
+
+ return ret;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdSpriteSet::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "SPRITESET {\n");
+ if (_name) Buffer->PutTextIndent(Indent + 2, "NAME=\"%s\"\n", _name);
+ for (int i = 0; i < NUM_DIRECTIONS; i++) {
+ if (_sprites[i]) {
+ switch (i) {
+ case DI_UP:
+ Buffer->PutTextIndent(Indent + 2, "UP=\"%s\"\n", _sprites[i]->_filename);
+ break;
+ case DI_UPRIGHT:
+ Buffer->PutTextIndent(Indent + 2, "UP_RIGHT=\"%s\"\n", _sprites[i]->_filename);
+ break;
+ case DI_RIGHT:
+ Buffer->PutTextIndent(Indent + 2, "RIGHT=\"%s\"\n", _sprites[i]->_filename);
+ break;
+ case DI_DOWNRIGHT:
+ Buffer->PutTextIndent(Indent + 2, "DOWN_RIGHT=\"%s\"\n", _sprites[i]->_filename);
+ break;
+ case DI_DOWN:
+ Buffer->PutTextIndent(Indent + 2, "DOWN=\"%s\"\n", _sprites[i]->_filename);
+ break;
+ case DI_DOWNLEFT:
+ Buffer->PutTextIndent(Indent + 2, "DOWN_LEFT=\"%s\"\n", _sprites[i]->_filename);
+ break;
+ case DI_LEFT:
+ Buffer->PutTextIndent(Indent + 2, "LEFT=\"%s\"\n", _sprites[i]->_filename);
+ break;
+ case DI_UPLEFT:
+ Buffer->PutTextIndent(Indent + 2, "UP_LEFT=\"%s\"\n", _sprites[i]->_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 (_sprites[i] == Sprite) return true;
+ }
+ return false;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdSpriteSet.h b/engines/wintermute/Ad/AdSpriteSet.h
new file mode 100644
index 0000000000..4da0fded12
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADSPRITESET_H
+#define WINTERMUTE_ADSPRITESET_H
+
+
+#include "engines/wintermute/BObject.h"
+#include "engines/wintermute/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 *_owner;
+ CAdSpriteSet(CBGame *inGame, CBObject *Owner = NULL);
+ virtual ~CAdSpriteSet();
+ HRESULT LoadFile(const char *Filename, int LifeTime = -1, TSpriteCacheType CacheType = CACHE_ALL);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true, int LifeTime = -1, TSpriteCacheType CacheType = CACHE_ALL);
+ CBSprite *_sprites[NUM_DIRECTIONS];
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdTalkDef.cpp b/engines/wintermute/Ad/AdTalkDef.cpp
new file mode 100644
index 0000000000..7a5091432f
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdTalkDef.h"
+#include "engines/wintermute/Ad/AdTalkNode.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/Ad/AdSpriteSet.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/utils.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdTalkDef, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkDef::CAdTalkDef(CBGame *inGame): CBObject(inGame) {
+ _defaultSpriteFilename = NULL;
+ _defaultSprite = NULL;
+
+ _defaultSpriteSetFilename = NULL;
+ _defaultSpriteSet = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkDef::~CAdTalkDef() {
+ for (int i = 0; i < _nodes.GetSize(); i++) delete _nodes[i];
+ _nodes.RemoveAll();
+
+ delete[] _defaultSpriteFilename;
+ delete _defaultSprite;
+ _defaultSpriteFilename = NULL;
+ _defaultSprite = NULL;
+
+ delete[] _defaultSpriteSetFilename;
+ delete _defaultSpriteSet;
+ _defaultSpriteSetFilename = NULL;
+ _defaultSpriteSet = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdTalkDef::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ CBUtils::SetString(&_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))) _nodes.Add(Node);
+ else {
+ delete Node;
+ Node = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ }
+ break;
+
+ case TOKEN_DEFAULT_SPRITE:
+ CBUtils::SetString(&_defaultSpriteFilename, (char *)params);
+ break;
+
+ case TOKEN_DEFAULT_SPRITESET_FILE:
+ CBUtils::SetString(&_defaultSpriteSetFilename, (char *)params);
+ break;
+
+ case TOKEN_DEFAULT_SPRITESET: {
+ delete _defaultSpriteSet;
+ _defaultSpriteSet = new CAdSpriteSet(Game);
+ if (!_defaultSpriteSet || FAILED(_defaultSpriteSet->LoadBuffer(params, false))) {
+ delete _defaultSpriteSet;
+ _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 _defaultSprite;
+ delete _defaultSpriteSet;
+ _defaultSprite = NULL;
+ _defaultSpriteSet = NULL;
+
+ if (_defaultSpriteFilename) {
+ _defaultSprite = new CBSprite(Game);
+ if (!_defaultSprite || FAILED(_defaultSprite->LoadFile(_defaultSpriteFilename))) return E_FAIL;
+ }
+
+ if (_defaultSpriteSetFilename) {
+ _defaultSpriteSet = new CAdSpriteSet(Game);
+ if (!_defaultSpriteSet || FAILED(_defaultSpriteSet->LoadFile(_defaultSpriteSetFilename))) return E_FAIL;
+ }
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_defaultSprite));
+ PersistMgr->Transfer(TMEMBER(_defaultSpriteFilename));
+ PersistMgr->Transfer(TMEMBER(_defaultSpriteSet));
+ PersistMgr->Transfer(TMEMBER(_defaultSpriteSetFilename));
+
+ _nodes.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkDef::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "TALK {\n");
+ if (_defaultSpriteFilename) Buffer->PutTextIndent(Indent + 2, "DEFAULT_SPRITE=\"%s\"\n", _defaultSpriteFilename);
+
+ if (_defaultSpriteSetFilename) Buffer->PutTextIndent(Indent + 2, "DEFAULT_SPRITESET_FILE=\"%s\"\n", _defaultSpriteSetFilename);
+ else if (_defaultSpriteSet) _defaultSpriteSet->SaveAsText(Buffer, Indent + 2);
+
+ for (int i = 0; i < _nodes.GetSize(); i++) {
+ _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 (_defaultSpriteFilename && !_defaultSprite) {
+ _defaultSprite = new CBSprite(Game);
+ if (!_defaultSprite || FAILED(_defaultSprite->LoadFile(_defaultSpriteFilename))) {
+ delete _defaultSprite;
+ _defaultSprite = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ } else if (_defaultSpriteSetFilename && !_defaultSpriteSet) {
+ _defaultSpriteSet = new CAdSpriteSet(Game);
+ if (!_defaultSpriteSet || FAILED(_defaultSpriteSet->LoadFile(_defaultSpriteSetFilename))) {
+ delete _defaultSpriteSet;
+ _defaultSpriteSet = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ } else return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdTalkDef::GetDefaultSprite(TDirection Dir) {
+ LoadDefaultSprite();
+ if (_defaultSprite) return _defaultSprite;
+ else if (_defaultSpriteSet) return _defaultSpriteSet->GetSprite(Dir);
+ else return NULL;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdTalkDef.h b/engines/wintermute/Ad/AdTalkDef.h
new file mode 100644
index 0000000000..7eaafcd6ec
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADTALKDEF_H
+#define WINTERMUTE_ADTALKDEF_H
+
+#include "engines/wintermute/coll_templ.h"
+#include "engines/wintermute/BObject.h"
+
+namespace WinterMute {
+class CAdTalkNode;
+class CAdSpriteSet;
+class CAdTalkDef : public CBObject {
+public:
+ char *_defaultSpriteSetFilename;
+ CAdSpriteSet *_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 *> _nodes;
+ char *_defaultSpriteFilename;
+ CBSprite *_defaultSprite;
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent = 0);
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdTalkHolder.cpp b/engines/wintermute/Ad/AdTalkHolder.cpp
new file mode 100644
index 0000000000..f5ae27967d
--- /dev/null
+++ b/engines/wintermute/Ad/AdTalkHolder.cpp
@@ -0,0 +1,356 @@
+/* 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
+ */
+
+#define FORBIDDEN_SYMBOL_EXCEPTION_rand
+#include "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdTalkHolder.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/scriptables/ScScript.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdTalkHolder, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkHolder::CAdTalkHolder(CBGame *inGame): CAdObject(inGame) {
+ _sprite = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkHolder::~CAdTalkHolder() {
+ delete _sprite;
+ _sprite = NULL;
+
+ int i;
+ for (i = 0; i < _talkSprites.GetSize(); i++) delete _talkSprites[i];
+ _talkSprites.RemoveAll();
+
+ for (i = 0; i < _talkSpritesEx.GetSize(); i++) delete _talkSpritesEx[i];
+ _talkSpritesEx.RemoveAll();
+}
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdTalkHolder::GetTalkStance(const char *Stance) {
+ CBSprite *ret = NULL;
+
+
+ // forced stance?
+ if (_forcedTalkAnimName && !_forcedTalkAnimUsed) {
+ _forcedTalkAnimUsed = true;
+ delete _animSprite;
+ _animSprite = new CBSprite(Game, this);
+ if (_animSprite) {
+ HRESULT res = _animSprite->LoadFile(_forcedTalkAnimName);
+ if (FAILED(res)) {
+ Game->LOG(res, "CAdTalkHolder::GetTalkStance: error loading talk sprite (object:\"%s\" sprite:\"%s\")", _name, _forcedTalkAnimName);
+ delete _animSprite;
+ _animSprite = NULL;
+ } else return _animSprite;
+ }
+ }
+
+
+ if (Stance != NULL) {
+ // search special talk stances
+ for (int i = 0; i < _talkSpritesEx.GetSize(); i++) {
+ if (scumm_stricmp(_talkSpritesEx[i]->_name, Stance) == 0) {
+ ret = _talkSpritesEx[i];
+ break;
+ }
+ }
+ if (ret == NULL) {
+ // serach generic talk stances
+ for (int i = 0; i < _talkSprites.GetSize(); i++) {
+ if (scumm_stricmp(_talkSprites[i]->_name, Stance) == 0) {
+ ret = _talkSprites[i];
+ break;
+ }
+ }
+ }
+ }
+
+ // not a valid stance? get a random one
+ if (ret == NULL) {
+ if (_talkSprites.GetSize() < 1) ret = _sprite;
+ else {
+ // TODO: remember last
+ int rnd = rand() % _talkSprites.GetSize();
+ ret = _talkSprites[rnd];
+ }
+ }
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetSprite
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetSprite") == 0) {
+ Stack->CorrectParams(1);
+
+ CScValue *Val = Stack->Pop();
+
+ bool SetCurrent = false;
+ if (_currentSprite && _currentSprite == _sprite) SetCurrent = true;
+
+ delete _sprite;
+ _sprite = NULL;
+
+ if (Val->IsNULL()) {
+ _sprite = NULL;
+ if (SetCurrent) _currentSprite = NULL;
+ Stack->PushBool(true);
+ } else {
+ const 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 {
+ _sprite = spr;
+ if (SetCurrent) _currentSprite = _sprite;
+ Stack->PushBool(true);
+ }
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetSprite") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!_sprite || !_sprite->_filename) Stack->PushNULL();
+ else Stack->PushString(_sprite->_filename);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetSpriteObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GetSpriteObject") == 0) {
+ Stack->CorrectParams(0);
+
+ if (!_sprite) Stack->PushNULL();
+ else Stack->PushNative(_sprite, true);
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddTalkSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddTalkSprite") == 0) {
+ Stack->CorrectParams(2);
+
+ const 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) _talkSpritesEx.Add(spr);
+ else _talkSprites.Add(spr);
+ Stack->PushBool(true);
+ }
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // RemoveTalkSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "RemoveTalkSprite") == 0) {
+ Stack->CorrectParams(2);
+
+ const char *Filename = Stack->Pop()->GetString();
+ bool Ex = Stack->Pop()->GetBool();
+ int i;
+
+ bool SetCurrent = false;
+ bool SetTemp2 = false;
+
+ if (Ex) {
+ for (i = 0; i < _talkSpritesEx.GetSize(); i++) {
+ if (scumm_stricmp(_talkSpritesEx[i]->_filename, Filename) == 0) {
+ if (_currentSprite == _talkSpritesEx[i]) SetCurrent = true;
+ if (_tempSprite2 == _talkSpritesEx[i]) SetTemp2 = true;
+ delete _talkSpritesEx[i];
+ _talkSpritesEx.RemoveAt(i);
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < _talkSprites.GetSize(); i++) {
+ if (scumm_stricmp(_talkSprites[i]->_filename, Filename) == 0) {
+ if (_currentSprite == _talkSprites[i]) SetCurrent = true;
+ if (_tempSprite2 == _talkSprites[i]) SetTemp2 = true;
+ delete _talkSprites[i];
+ _talkSprites.RemoveAt(i);
+ break;
+ }
+ }
+
+ }
+
+ Stack->PushBool(true);
+ if (SetCurrent) _currentSprite = _sprite;
+ if (SetTemp2) _tempSprite2 = _sprite;
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetTalkSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SetTalkSprite") == 0) {
+ Stack->CorrectParams(2);
+
+ const 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 < _talkSpritesEx.GetSize(); i++) {
+ if (_talkSpritesEx[i] == _currentSprite) SetCurrent = true;
+ if (_talkSpritesEx[i] == _tempSprite2) SetTemp2 = true;
+ delete _talkSpritesEx[i];
+ }
+ _talkSpritesEx.RemoveAll();
+ } else {
+ for (i = 0; i < _talkSprites.GetSize(); i++) {
+ if (_talkSprites[i] == _currentSprite) SetCurrent = true;
+ if (_talkSprites[i] == _tempSprite2) SetTemp2 = true;
+ delete _talkSprites[i];
+ }
+ _talkSprites.RemoveAll();
+ }
+
+ // set new
+ if (Ex) _talkSpritesEx.Add(spr);
+ else _talkSprites.Add(spr);
+ Stack->PushBool(true);
+
+ if (SetCurrent) _currentSprite = spr;
+ if (SetTemp2) _tempSprite2 = spr;
+ }
+ return S_OK;
+ }
+
+ else return CAdObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdTalkHolder::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type (RO)
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("talk-holder");
+ return _scValue;
+ }
+
+ else return CAdObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::ScSetProperty(const char *Name, CScValue *Value) {
+ /*
+ //////////////////////////////////////////////////////////////////////////
+ // Item
+ //////////////////////////////////////////////////////////////////////////
+ if(strcmp(Name, "Item")==0){
+ SetItem(Value->GetString());
+ return S_OK;
+ }
+
+ else*/ return CAdObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CAdTalkHolder::ScToString() {
+ return "[talk-holder object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ int i;
+ for (i = 0; i < _talkSprites.GetSize(); i++) {
+ if (_talkSprites[i]->_filename)
+ Buffer->PutTextIndent(Indent + 2, "TALK=\"%s\"\n", _talkSprites[i]->_filename);
+ }
+
+ for (i = 0; i < _talkSpritesEx.GetSize(); i++) {
+ if (_talkSpritesEx[i]->_filename)
+ Buffer->PutTextIndent(Indent + 2, "TALK_SPECIAL=\"%s\"\n", _talkSpritesEx[i]->_filename);
+ }
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkHolder::Persist(CBPersistMgr *PersistMgr) {
+ CAdObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_sprite));
+ _talkSprites.Persist(PersistMgr);
+ _talkSpritesEx.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdTalkHolder.h b/engines/wintermute/Ad/AdTalkHolder.h
new file mode 100644
index 0000000000..7c10783057
--- /dev/null
+++ b/engines/wintermute/Ad/AdTalkHolder.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 WINTERMUTE_ADTALKHOLDER_H
+#define WINTERMUTE_ADTALKHOLDER_H
+
+#include "engines/wintermute/Ad/AdObject.h"
+
+namespace WinterMute {
+
+class CAdTalkHolder : public CAdObject {
+public:
+ DECLARE_PERSISTENT(CAdTalkHolder, CAdObject)
+ virtual CBSprite *GetTalkStance(const char *Stance);
+ virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
+ CBSprite *_sprite;
+ CBArray<CBSprite *, CBSprite *> _talkSprites;
+ CBArray<CBSprite *, CBSprite *> _talkSpritesEx;
+ CAdTalkHolder(CBGame *inGame);
+ virtual ~CAdTalkHolder();
+
+ // scripting interface
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+ virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name);
+ virtual const char *ScToString();
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdTalkNode.cpp b/engines/wintermute/Ad/AdTalkNode.cpp
new file mode 100644
index 0000000000..f2f35539ff
--- /dev/null
+++ b/engines/wintermute/Ad/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 "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Ad/AdTalkNode.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/Ad/AdSpriteSet.h"
+#include "engines/wintermute/utils.h"
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdTalkNode, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkNode::CAdTalkNode(CBGame *inGame): CBBase(inGame) {
+ _sprite = NULL;
+ _spriteFilename = NULL;
+ _spriteSet = NULL;
+ _spriteSetFilename = NULL;
+ _comment = NULL;
+
+ _startTime = _endTime = 0;
+ _playToEnd = false;
+ _preCache = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdTalkNode::~CAdTalkNode() {
+ delete[] _spriteFilename;
+ delete _sprite;
+ delete[] _spriteSetFilename;
+ delete _spriteSet;
+ delete _comment;
+ _spriteFilename = NULL;
+ _sprite = NULL;
+ _spriteSetFilename = NULL;
+ _spriteSet = NULL;
+ _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;
+ }
+
+ _endTime = 0;
+ _playToEnd = false;
+ _preCache = false;
+
+ while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_SPRITE:
+ CBUtils::SetString(&_spriteFilename, (char *)params);
+ break;
+
+ case TOKEN_SPRITESET_FILE:
+ CBUtils::SetString(&_spriteSetFilename, (char *)params);
+ break;
+
+ case TOKEN_SPRITESET: {
+ delete _spriteSet;
+ _spriteSet = new CAdSpriteSet(Game);
+ if (!_spriteSet || FAILED(_spriteSet->LoadBuffer(params, false))) {
+ delete _spriteSet;
+ _spriteSet = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ }
+ break;
+
+ case TOKEN_START_TIME:
+ parser.ScanStr((char *)params, "%d", &_startTime);
+ break;
+
+ case TOKEN_END_TIME:
+ parser.ScanStr((char *)params, "%d", &_endTime);
+ break;
+
+ case TOKEN_PRECACHE:
+ parser.ScanStr((char *)params, "%b", &_preCache);
+ break;
+
+ case TOKEN_COMMENT:
+ if (Game->_editorMode) CBUtils::SetString(&_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 (_endTime == 0) _playToEnd = true;
+ else _playToEnd = false;
+
+ if (_preCache && _spriteFilename) {
+ delete _sprite;
+ _sprite = new CBSprite(Game);
+ if (!_sprite || FAILED(_sprite->LoadFile(_spriteFilename))) return E_FAIL;
+ }
+
+ if (_preCache && _spriteSetFilename) {
+ delete _spriteSet;
+ _spriteSet = new CAdSpriteSet(Game);
+ if (!_spriteSet || FAILED(_spriteSet->LoadFile(_spriteSetFilename))) return E_FAIL;
+ }
+
+
+ return S_OK;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkNode::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(_comment));
+ PersistMgr->Transfer(TMEMBER(_startTime));
+ PersistMgr->Transfer(TMEMBER(_endTime));
+ PersistMgr->Transfer(TMEMBER(_playToEnd));
+ PersistMgr->Transfer(TMEMBER(_sprite));
+ PersistMgr->Transfer(TMEMBER(_spriteFilename));
+ PersistMgr->Transfer(TMEMBER(_spriteSet));
+ PersistMgr->Transfer(TMEMBER(_spriteSetFilename));
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkNode::SaveAsText(CBDynBuffer *Buffer, int Indent) {
+ Buffer->PutTextIndent(Indent, "ACTION {\n");
+ if (_comment) Buffer->PutTextIndent(Indent + 2, "COMMENT=\"%s\"\n", _comment);
+ Buffer->PutTextIndent(Indent + 2, "START_TIME=%d\n", _startTime);
+ if (!_playToEnd) Buffer->PutTextIndent(Indent + 2, "END_TIME=%d\n", _endTime);
+ if (_spriteFilename) Buffer->PutTextIndent(Indent + 2, "SPRITE=\"%s\"\n", _spriteFilename);
+ if (_spriteSetFilename) Buffer->PutTextIndent(Indent + 2, "SPRITESET_FILE=\"%s\"\n", _spriteSetFilename);
+ else if (_spriteSet) _spriteSet->SaveAsText(Buffer, Indent + 2);
+ if (_preCache) Buffer->PutTextIndent(Indent + 2, "PRECACHE=\"%s\"\n", _preCache ? "TRUE" : "FALSE");
+
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdTalkNode::LoadSprite() {
+ if (_spriteFilename && !_sprite) {
+ _sprite = new CBSprite(Game);
+ if (!_sprite || FAILED(_sprite->LoadFile(_spriteFilename))) {
+ delete _sprite;
+ _sprite = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ }
+
+ else if (_spriteSetFilename && !_spriteSet) {
+ _spriteSet = new CAdSpriteSet(Game);
+ if (!_spriteSet || FAILED(_spriteSet->LoadFile(_spriteSetFilename))) {
+ delete _spriteSet;
+ _spriteSet = NULL;
+ return E_FAIL;
+ } else return S_OK;
+ }
+
+ else return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CAdTalkNode::IsInTimeInterval(uint32 Time, TDirection Dir) {
+ if (Time >= _startTime) {
+ if (_playToEnd) {
+ if ((_spriteFilename && _sprite == NULL) || (_sprite && _sprite->_finished == false)) return true;
+ else if ((_spriteSetFilename && _spriteSet == NULL) || (_spriteSet && _spriteSet->GetSprite(Dir) && _spriteSet->GetSprite(Dir)->_finished == false)) return true;
+ else return false;
+ } else return _endTime >= Time;
+ } else return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CBSprite *CAdTalkNode::GetSprite(TDirection Dir) {
+ LoadSprite();
+ if (_sprite) return _sprite;
+ else if (_spriteSet) return _spriteSet->GetSprite(Dir);
+ else return NULL;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdTalkNode.h b/engines/wintermute/Ad/AdTalkNode.h
new file mode 100644
index 0000000000..18781f90da
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADTALKNODE_H
+#define WINTERMUTE_ADTALKNODE_H
+
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/BBase.h"
+
+namespace WinterMute {
+class CAdSpriteSet;
+class CBSprite;
+class CAdTalkNode : public CBBase {
+public:
+ char *_spriteSetFilename;
+ CAdSpriteSet *_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 *_spriteFilename;
+ CBSprite *_sprite;
+ uint32 _startTime;
+ uint32 _endTime;
+ bool _playToEnd;
+ bool _preCache;
+ char *_comment;
+
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/Ad/AdTypes.h b/engines/wintermute/Ad/AdTypes.h
new file mode 100644
index 0000000000..6531927350
--- /dev/null
+++ b/engines/wintermute/Ad/AdTypes.h
@@ -0,0 +1,93 @@
+/* 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 WINTERMUTE_ADTYPES_H
+#define WINTERMUTE_ADTYPES_H
+
+namespace WinterMute {
+
+typedef enum {
+ GAME_NORMAL, GAME_WAITING_RESPONSE
+} TGameStateEx;
+
+
+typedef enum {
+ OBJECT_ENTITY, OBJECT_REGION, OBJECT_ACTOR, OBJECT_NONE
+} TObjectType;
+
+
+typedef enum {
+ ENTITY_NORMAL, ENTITY_SOUND
+} TEntityType;
+
+
+typedef enum {
+ STATE_NONE,
+ STATE_IDLE,
+ STATE_PLAYING_ANIM,
+ STATE_READY,
+ STATE_FOLLOWING_PATH,
+ STATE_SEARCHING_PATH,
+ STATE_WAITING_PATH,
+ STATE_TURNING_LEFT,
+ STATE_TURNING_RIGHT,
+ STATE_TURNING,
+ STATE_TALKING,
+ STATE_DIRECT_CONTROL,
+ STATE_PLAYING_ANIM_SET
+} TObjectState;
+
+typedef enum {
+ DIRECT_WALK_NONE, DIRECT_WALK_FW, DIRECT_WALK_BK
+} TDirectWalkMode;
+
+typedef enum {
+ DIRECT_TURN_NONE, DIRECT_TURN_CW, DIRECT_TURN_CCW
+} TDirectTurnMode;
+
+typedef enum {
+ RESPONSE_TEXT, RESPONSE_ICON
+} TResponseStyle;
+
+typedef enum {
+ RESPONSE_ALWAYS, RESPONSE_ONCE, RESPONSE_ONCE_GAME
+} TResponseType;
+
+
+typedef enum {
+ TALK_SKIP_LEFT = 0, TALK_SKIP_RIGHT = 1, TALK_SKIP_BOTH = 2, TALK_SKIP_NONE = 3
+} TTalkSkipButton;
+
+
+typedef enum {
+ GEOM_WAYPOINT, GEOM_WALKPLANE, GEOM_BLOCKED, GEOM_GENERIC
+} TGeomNodeType;
+
+} // end of namespace WinterMute
+
+#endif // WINTERMUTE_ADTYPES_H
diff --git a/engines/wintermute/Ad/AdWaypointGroup.cpp b/engines/wintermute/Ad/AdWaypointGroup.cpp
new file mode 100644
index 0000000000..982079269e
--- /dev/null
+++ b/engines/wintermute/Ad/AdWaypointGroup.cpp
@@ -0,0 +1,262 @@
+/* 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 "engines/wintermute/Ad/AdWaypointGroup.h"
+#include "engines/wintermute/BParser.h"
+#include "engines/wintermute/BDynBuffer.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BRegion.h"
+#include "engines/wintermute/BFileManager.h"
+#include <limits.h>
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CAdWaypointGroup, false)
+
+//////////////////////////////////////////////////////////////////////////
+CAdWaypointGroup::CAdWaypointGroup(CBGame *inGame): CBObject(inGame) {
+ _active = true;
+ _editorSelectedPoint = -1;
+ _lastMimicScale = -1;
+ _lastMimicX = _lastMimicY = INT_MIN;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CAdWaypointGroup::~CAdWaypointGroup() {
+ Cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CAdWaypointGroup::Cleanup() {
+ for (int i = 0; i < _points.GetSize(); i++)
+ delete _points[i];
+ _points.RemoveAll();
+ _editorSelectedPoint = -1;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::LoadFile(const char *Filename) {
+ byte *Buffer = Game->_fileManager->ReadWholeFile(Filename);
+ if (Buffer == NULL) {
+ Game->LOG(0, "CAdWaypointGroup::LoadFile failed for file '%s'", Filename);
+ return E_FAIL;
+ }
+
+ HRESULT ret;
+
+ _filename = new char [strlen(Filename) + 1];
+ strcpy(_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);
+ _points.Add(new CBPoint(x, y));
+ }
+ break;
+
+ case TOKEN_EDITOR_SELECTED:
+ parser.ScanStr((char *)params, "%b", &_editorSelected);
+ break;
+
+ case TOKEN_EDITOR_SELECTED_POINT:
+ parser.ScanStr((char *)params, "%d", &_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", _name);
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED=%s\n", _editorSelected ? "TRUE" : "FALSE");
+ Buffer->PutTextIndent(Indent + 2, "EDITOR_SELECTED_POINT=%d\n", _editorSelectedPoint);
+
+ if (_scProp) _scProp->SaveAsText(Buffer, Indent + 2);
+ CBBase::SaveAsText(Buffer, Indent + 2);
+
+ for (int i = 0; i < _points.GetSize(); i++) {
+ Buffer->PutTextIndent(Indent + 2, "POINT {%d,%d}\n", _points[i]->x, _points[i]->y);
+ }
+
+ Buffer->PutTextIndent(Indent, "}\n");
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::Persist(CBPersistMgr *PersistMgr) {
+
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(_active));
+ PersistMgr->Transfer(TMEMBER(_editorSelectedPoint));
+ PersistMgr->Transfer(TMEMBER(_lastMimicScale));
+ PersistMgr->Transfer(TMEMBER(_lastMimicX));
+ PersistMgr->Transfer(TMEMBER(_lastMimicY));
+ _points.Persist(PersistMgr);
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CAdWaypointGroup::ScGetProperty(const char *Name) {
+ _scValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ _scValue->SetString("waypoint-group");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Active") == 0) {
+ _scValue->SetBool(_active);
+ return _scValue;
+ }
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CAdWaypointGroup::ScSetProperty(const char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Active
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Active") == 0) {
+ _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 == _lastMimicScale && X == _lastMimicX && Y == _lastMimicY) return S_OK;
+
+ Cleanup();
+
+ for (int i = 0; i < Wpt->_points.GetSize(); i++) {
+ int x, y;
+
+ x = (int)((float)Wpt->_points[i]->x * Scale / 100.0f);
+ y = (int)((float)Wpt->_points[i]->y * Scale / 100.0f);
+
+ _points.Add(new CBPoint(x + X, y + Y));
+ }
+
+ _lastMimicScale = Scale;
+ _lastMimicX = X;
+ _lastMimicY = Y;
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Ad/AdWaypointGroup.h b/engines/wintermute/Ad/AdWaypointGroup.h
new file mode 100644
index 0000000000..ea76bb50fa
--- /dev/null
+++ b/engines/wintermute/Ad/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 WINTERMUTE_ADWAYPOINTGROUP_H
+#define WINTERMUTE_ADWAYPOINTGROUP_H
+
+#include "engines/wintermute/BObject.h"
+
+namespace WinterMute {
+class CBPoint;
+class CAdWaypointGroup : public CBObject {
+public:
+ float _lastMimicScale;
+ int _lastMimicX;
+ int _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 _active;
+ CAdWaypointGroup(CBGame *inGame);
+ HRESULT LoadFile(const char *Filename);
+ HRESULT LoadBuffer(byte *Buffer, bool Complete = true);
+ virtual ~CAdWaypointGroup();
+ CBArray<CBPoint *, CBPoint *> _points;
+ int _editorSelectedPoint;
+ virtual CScValue *ScGetProperty(const char *Name);
+ virtual HRESULT ScSetProperty(const char *Name, CScValue *Value);
+};
+
+} // end of namespace WinterMute
+
+#endif