Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

speech.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * Additional copyright for this file:
 * Copyright (C) 1994-1998 Revolution Software Ltd.
 *
 * This program is free software; you can 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.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/engines/sword2/speech.cpp $
 * $Id: speech.cpp 30944 2008-02-23 22:50:18Z sev $
 */


#include "common/file.h"

#include "sword2/sword2.h"
#include "sword2/defs.h"
#include "sword2/header.h"
#include "sword2/console.h"
#include "sword2/logic.h"
#include "sword2/maketext.h"
#include "sword2/object.h"
#include "sword2/resman.h"
#include "sword2/screen.h"

namespace Sword2 {

// To request the status of a target, we run its 4th script, get-speech-state.
// This will cause RESULT to be set to either 1 (target is waiting) or 0
// (target is busy).

// Distance kept above talking sprite
#define GAP_ABOVE_HEAD 20

enum {
      S_OB_GRAPHIC      = 0,
      S_OB_SPEECH = 1,
      S_OB_LOGIC  = 2,
      S_OB_MEGA   = 3,

      S_TEXT            = 4,
      S_WAV       = 5,
      S_ANIM            = 6,
      S_DIR_TABLE = 7,
      S_ANIM_MODE = 8
};

/**
 * Sets _textX and _textY for position of text sprite. Note that _textX is
 * also used to calculate speech pan.
 */

void Logic::locateTalker(int32 *params) {
      // params:  0 pointer to ob_graphic
      //          1 pointer to ob_speech
      //          2 pointer to ob_logic
      //          3 pointer to ob_mega
      //          4 encoded text number
      //          5 wav res id
      //          6 anim res id
      //          7 pointer to anim table
      //          8 animation mode  0 lip synced,
      //                            1 just straight animation

      if (!_animId) {
            // There is no animation. Assume it's voice-over text, and put
            // it at the bottom of the screen.

            _textX = 320;
            _textY = 400;
            return;
      }

      byte *file = _vm->_resman->openResource(_animId);

      // '0' means 1st frame

      CdtEntry cdt_entry;
      FrameHeader frame_head;

      cdt_entry.read(_vm->fetchCdtEntry(file, 0));
      frame_head.read(_vm->fetchFrameHeader(file, 0));

      // Note: This part of the code is quite similar to registerFrame().

      if (cdt_entry.frameType & FRAME_OFFSET) {
            // The frame has offsets, i.e. it's a scalable mega frame
            ObjectMega obMega(decodePtr(params[S_OB_MEGA]));

            uint16 scale = obMega.calcScale();

            // Calc suitable centre point above the head, based on scaled
            // height

            // just use 'feet_x' as centre
            _textX = obMega.getFeetX();

            // Add scaled y-offset to feet_y coord to get top of sprite
            _textY = obMega.getFeetY() + (cdt_entry.y * scale) / 256;
      } else {
            // It's a non-scaling anim - calc suitable centre point above
            // the head, based on scaled width

            // x-coord + half of width
            _textX = cdt_entry.x + frame_head.width / 2;
            _textY = cdt_entry.y;
      }

      _vm->_resman->closeResource(_animId);

      // Leave space above their head
      _textY -= GAP_ABOVE_HEAD;

      // Adjust the text coords for RDSPR_DISPLAYALIGN

      ScreenInfo *screenInfo = _vm->_screen->getScreenInfo();

      _textX -= screenInfo->scroll_offset_x;
      _textY -= screenInfo->scroll_offset_y;
}

/**
 * This function is called the first time to build the text, if we need one. If
 * If necessary it also brings in the wav and sets up the animation.
 *
 * If there is an animation it can be repeating lip-sync or run-once.
 *
 * If there is no wav, then the text comes up instead. There can be any
 * combination of text/wav playing.
 */

void Logic::formText(int32 *params) {
      // params   0 pointer to ob_graphic
      //          1 pointer to ob_speech
      //          2 pointer to ob_logic
      //          3 pointer to ob_mega
      //          4 encoded text number
      //          5 wav res id
      //          6 anim res id
      //          7 pointer to anim table
      //          8 animation mode  0 lip synced,
      //                            1 just straight animation

      // There should always be a text line, as all text is derived from it.
      // If there is none, that's bad...

      if (!params[S_TEXT]) {
            warning("No text line for speech wav %d", params[S_WAV]);
            return;
      }

      ObjectSpeech obSpeech(decodePtr(params[S_OB_SPEECH]));

      // Establish the max width allowed for this text sprite.
      uint32 textWidth = obSpeech.getWidth();

      if (!textWidth)
            textWidth = 400;

      // Pull out the text line, and make the sprite and text block

      uint32 text_res = params[S_TEXT] / SIZE;
      uint32 local_text = params[S_TEXT] & 0xffff;
      byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);

      // 'text + 2' to skip the first 2 bytes which form the line reference
      // number

      _speechTextBlocNo = _vm->_fontRenderer->buildNewBloc(
            text + 2, _textX, _textY,
            textWidth, obSpeech.getPen(),
            RDSPR_TRANS | RDSPR_DISPLAYALIGN,
            _vm->_speechFontId, POSITION_AT_CENTRE_OF_BASE);

      _vm->_resman->closeResource(text_res);

      // Set speech duration, in case not using a wav.
      _speechTime = strlen((char *)text) + 30;
}

/**
 * There are some hard-coded cases where speech is used to illustrate a sound
 * effect. In this case there is no sound associated with the speech itself.
 */

bool Logic::wantSpeechForLine(uint32 wavId) {
      switch (wavId) {
      case 1328:  // AttendantSpeech
                  //    SFX(Phone71);
                  //    FX <Telephone rings>
      case 2059:  // PabloSpeech
                  //    SFX (2059);
                  //    FX <Sound of sporadic gunfire from below>
      case 4082:  // DuaneSpeech
                  //    SFX (4082);
                  //    FX <Pffffffffffft! Frp. (Unimpressive, flatulent noise.)>
      case 4214:  // cat_52
                  //    SFX (4214);
                  //    4214FXMeow!
      case 4568:  // trapdoor_13
                  //    SFX (4568);
                  //    4568fx<door slamming>
      case 4913:  // LobineauSpeech
                  //    SFX (tone2);
                  //    FX <Lobineau hangs up>
      case 5120:  // bush_66
                  //    SFX (5120);
                  //    5120FX<loud buzzing>
      case 528:   // PresidentaSpeech
                  //    SFX (528);
                  //    FX <Nearby Crash of Collapsing Masonry>
      case 920:   // Zombie Island forest maze (bird)
      case 923:   // Zombie Island forest maze (monkey)
      case 926:   // Zombie Island forest maze (zombie)
            // Don't want speech for these lines!
            return false;
      default:
            // Ok for all other lines
            return true;
      }
}

} // End of namespace Sword2

Generated by  Doxygen 1.6.0   Back to index