From 2317b3538fc5148dc9c7b3d26c2d60fdb06c85e4 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Sat, 2 Jun 2012 01:17:46 +0200 Subject: WINTERMUTE: Move all the Ad files to Ad/ --- engines/wintermute/Ad/AdActor.cpp | 1339 +++++++++++++ engines/wintermute/Ad/AdActor.h | 107 ++ engines/wintermute/Ad/AdActorDir.cpp | 52 + engines/wintermute/Ad/AdActorDir.h | 46 + engines/wintermute/Ad/AdEntity.cpp | 977 ++++++++++ engines/wintermute/Ad/AdEntity.h | 67 + engines/wintermute/Ad/AdGame.cpp | 2060 ++++++++++++++++++++ engines/wintermute/Ad/AdGame.h | 162 ++ engines/wintermute/Ad/AdInventory.cpp | 119 ++ engines/wintermute/Ad/AdInventory.h | 52 + engines/wintermute/Ad/AdInventoryBox.cpp | 373 ++++ engines/wintermute/Ad/AdInventoryBox.h | 63 + engines/wintermute/Ad/AdItem.cpp | 758 ++++++++ engines/wintermute/Ad/AdItem.h | 70 + engines/wintermute/Ad/AdLayer.cpp | 538 ++++++ engines/wintermute/Ad/AdLayer.h | 58 + engines/wintermute/Ad/AdNodeState.cpp | 169 ++ engines/wintermute/Ad/AdNodeState.h | 58 + engines/wintermute/Ad/AdObject.cpp | 1203 ++++++++++++ engines/wintermute/Ad/AdObject.h | 123 ++ engines/wintermute/Ad/AdPath.cpp | 112 ++ engines/wintermute/Ad/AdPath.h | 56 + engines/wintermute/Ad/AdPathPoint.cpp | 75 + engines/wintermute/Ad/AdPathPoint.h | 50 + engines/wintermute/Ad/AdRegion.cpp | 394 ++++ engines/wintermute/Ad/AdRegion.h | 58 + engines/wintermute/Ad/AdResponse.cpp | 143 ++ engines/wintermute/Ad/AdResponse.h | 61 + engines/wintermute/Ad/AdResponseBox.cpp | 645 +++++++ engines/wintermute/Ad/AdResponseBox.h | 85 + engines/wintermute/Ad/AdResponseContext.cpp | 70 + engines/wintermute/Ad/AdResponseContext.h | 50 + engines/wintermute/Ad/AdRotLevel.cpp | 159 ++ engines/wintermute/Ad/AdRotLevel.h | 49 + engines/wintermute/Ad/AdScaleLevel.cpp | 157 ++ engines/wintermute/Ad/AdScaleLevel.h | 50 + engines/wintermute/Ad/AdScene.cpp | 2763 +++++++++++++++++++++++++++ engines/wintermute/Ad/AdScene.h | 181 ++ engines/wintermute/Ad/AdSceneNode.cpp | 83 + engines/wintermute/Ad/AdSceneNode.h | 54 + engines/wintermute/Ad/AdSceneState.cpp | 88 + engines/wintermute/Ad/AdSceneState.h | 51 + engines/wintermute/Ad/AdSentence.cpp | 317 +++ engines/wintermute/Ad/AdSentence.h | 83 + engines/wintermute/Ad/AdSpriteSet.cpp | 313 +++ engines/wintermute/Ad/AdSpriteSet.h | 54 + engines/wintermute/Ad/AdTalkDef.cpp | 260 +++ engines/wintermute/Ad/AdTalkDef.h | 58 + engines/wintermute/Ad/AdTalkHolder.cpp | 356 ++++ engines/wintermute/Ad/AdTalkHolder.h | 57 + engines/wintermute/Ad/AdTalkNode.cpp | 263 +++ engines/wintermute/Ad/AdTalkNode.h | 63 + engines/wintermute/Ad/AdTypes.h | 93 + engines/wintermute/Ad/AdWaypointGroup.cpp | 262 +++ engines/wintermute/Ad/AdWaypointGroup.h | 58 + 55 files changed, 16065 insertions(+) create mode 100644 engines/wintermute/Ad/AdActor.cpp create mode 100644 engines/wintermute/Ad/AdActor.h create mode 100644 engines/wintermute/Ad/AdActorDir.cpp create mode 100644 engines/wintermute/Ad/AdActorDir.h create mode 100644 engines/wintermute/Ad/AdEntity.cpp create mode 100644 engines/wintermute/Ad/AdEntity.h create mode 100644 engines/wintermute/Ad/AdGame.cpp create mode 100644 engines/wintermute/Ad/AdGame.h create mode 100644 engines/wintermute/Ad/AdInventory.cpp create mode 100644 engines/wintermute/Ad/AdInventory.h create mode 100644 engines/wintermute/Ad/AdInventoryBox.cpp create mode 100644 engines/wintermute/Ad/AdInventoryBox.h create mode 100644 engines/wintermute/Ad/AdItem.cpp create mode 100644 engines/wintermute/Ad/AdItem.h create mode 100644 engines/wintermute/Ad/AdLayer.cpp create mode 100644 engines/wintermute/Ad/AdLayer.h create mode 100644 engines/wintermute/Ad/AdNodeState.cpp create mode 100644 engines/wintermute/Ad/AdNodeState.h create mode 100644 engines/wintermute/Ad/AdObject.cpp create mode 100644 engines/wintermute/Ad/AdObject.h create mode 100644 engines/wintermute/Ad/AdPath.cpp create mode 100644 engines/wintermute/Ad/AdPath.h create mode 100644 engines/wintermute/Ad/AdPathPoint.cpp create mode 100644 engines/wintermute/Ad/AdPathPoint.h create mode 100644 engines/wintermute/Ad/AdRegion.cpp create mode 100644 engines/wintermute/Ad/AdRegion.h create mode 100644 engines/wintermute/Ad/AdResponse.cpp create mode 100644 engines/wintermute/Ad/AdResponse.h create mode 100644 engines/wintermute/Ad/AdResponseBox.cpp create mode 100644 engines/wintermute/Ad/AdResponseBox.h create mode 100644 engines/wintermute/Ad/AdResponseContext.cpp create mode 100644 engines/wintermute/Ad/AdResponseContext.h create mode 100644 engines/wintermute/Ad/AdRotLevel.cpp create mode 100644 engines/wintermute/Ad/AdRotLevel.h create mode 100644 engines/wintermute/Ad/AdScaleLevel.cpp create mode 100644 engines/wintermute/Ad/AdScaleLevel.h create mode 100644 engines/wintermute/Ad/AdScene.cpp create mode 100644 engines/wintermute/Ad/AdScene.h create mode 100644 engines/wintermute/Ad/AdSceneNode.cpp create mode 100644 engines/wintermute/Ad/AdSceneNode.h create mode 100644 engines/wintermute/Ad/AdSceneState.cpp create mode 100644 engines/wintermute/Ad/AdSceneState.h create mode 100644 engines/wintermute/Ad/AdSentence.cpp create mode 100644 engines/wintermute/Ad/AdSentence.h create mode 100644 engines/wintermute/Ad/AdSpriteSet.cpp create mode 100644 engines/wintermute/Ad/AdSpriteSet.h create mode 100644 engines/wintermute/Ad/AdTalkDef.cpp create mode 100644 engines/wintermute/Ad/AdTalkDef.h create mode 100644 engines/wintermute/Ad/AdTalkHolder.cpp create mode 100644 engines/wintermute/Ad/AdTalkHolder.h create mode 100644 engines/wintermute/Ad/AdTalkNode.cpp create mode 100644 engines/wintermute/Ad/AdTalkNode.h create mode 100644 engines/wintermute/Ad/AdTypes.h create mode 100644 engines/wintermute/Ad/AdWaypointGroup.cpp create mode 100644 engines/wintermute/Ad/AdWaypointGroup.h (limited to 'engines/wintermute/Ad') 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 + +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 **)¶ms) != 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 **)¶ms)) > 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 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 **)¶ms)) > 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 _talkSprites; + CBArray _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 _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 **)¶ms) != 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 **)¶ms)) > 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 **)¶ms)) > 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 **)¶ms, commands, (char **)¶ms2)) > 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 **)¶ms)) > 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 _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 _items; + CAdObject *_inventoryOwner; + bool IsItemTaken(char *ItemName); + HRESULT RegisterInventory(CAdInventory *Inv); + HRESULT UnregisterInventory(CAdInventory *Inv); + + CAdObject *_invObject; + CBArray _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 _objects; + CBArray _sentences; + + CBArray _sceneStates; + CBArray _dlgPendingBranches; + + CBArray _responsesBranch; + CBArray _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 _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 + + +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 **)¶ms) != 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 **)¶ms)) > 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 **)¶ms) != 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 **)¶ms)) > 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 **)¶ms) != TOKEN_LAYER) { + Game->LOG(0, "'LAYER' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 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 _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 _attachmentsPre; + CBArray _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 _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 **)¶ms) != 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 **)¶ms)) > 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 **)¶ms) != TOKEN_RESPONSE_BOX) { + Game->LOG(0, "'RESPONSE_BOX' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 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 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 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 &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 &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 _responses; + CBArray _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 **)¶ms) != TOKEN_ROTATION_LEVEL) { + Game->LOG(0, "'ROTATION_LEVEL' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 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 **)¶ms) != TOKEN_SCALE_LEVEL) { + Game->LOG(0, "'SCALE_LEVEL' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 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 +#include + +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 **)¶ms) != 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 **)¶ms)) > 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 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 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 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 &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 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 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 &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 &Objects, bool InteractiveOnly); + HRESULT GetRegionObjects(CAdRegion *Region, CBArray &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 _layers; + CBArray _objects; + CBArray _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 _scaleLevels; + CBArray _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 _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 _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 **)¶ms) != TOKEN_SPRITESET) { + Game->LOG(0, "'SPRITESET' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + CBSprite *spr = NULL; + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 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 **)¶ms) != TOKEN_TALK) { + Game->LOG(0, "'TALK' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 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 _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 _talkSprites; + CBArray _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 **)¶ms) != 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 **)¶ms)) > 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 + +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 **)¶ms) != TOKEN_WAYPOINTS) { + Game->LOG(0, "'WAYPOINTS' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 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 _points; + int _editorSelectedPoint; + virtual CScValue *ScGetProperty(const char *Name); + virtual HRESULT ScSetProperty(const char *Name, CScValue *Value); +}; + +} // end of namespace WinterMute + +#endif -- cgit v1.2.3