scummvm/sword2/speech.cpp

229 lines
6.1 KiB
C++
Raw Normal View History

/* Copyright (C) 1994-1998 Revolution Software Ltd.
* Copyright (C) 2003-2005 The ScummVM project
2003-07-28 01:44:38 +00:00
*
* 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.
2003-07-28 01:44:38 +00:00
*
* $Header$
*/
#include "common/stdafx.h"
#include "common/file.h"
2004-11-14 15:00:01 +00:00
#include "sword2/sword2.h"
#include "sword2/console.h"
2003-10-28 19:51:30 +00:00
#include "sword2/defs.h"
#include "sword2/logic.h"
#include "sword2/maketext.h"
#include "sword2/resman.h"
2003-09-20 12:43:52 +00:00
2003-10-04 00:52:27 +00:00
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
2003-07-28 01:44:38 +00:00
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
};
2003-09-20 12:43:52 +00:00
/**
* Sets _textX and _textY for position of text sprite. Note that _textX is
* also used to calculate speech pan.
*/
2003-07-28 01:44:38 +00:00
void Logic::locateTalker(int32 *params) {
2003-09-20 12:43:52 +00:00
// 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
2003-07-28 01:44:38 +00:00
if (!_animId) {
// There is no animation. Assume it's voice-over text, and put
// it at the bottom of the screen.
2003-09-20 12:43:52 +00:00
_textX = 320;
_textY = 400;
return;
}
2003-07-28 01:44:38 +00:00
byte *file = _vm->_resman->openResource(_animId);
2003-07-28 01:44:38 +00:00
// '0' means 1st frame
2003-07-28 01:44:38 +00:00
CdtEntry cdt_entry;
FrameHeader frame_head;
cdt_entry.read(_vm->fetchCdtEntry(file, 0));
frame_head.read(_vm->fetchFrameHeader(file, 0));
2003-07-28 01:44:38 +00:00
// Note: This part of the code is quite similar to registerFrame().
2003-07-28 01:44:38 +00:00
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]));
2003-07-28 01:44:38 +00:00
uint16 scale = obMega.calcScale();
2003-07-28 01:44:38 +00:00
// Calc suitable centre point above the head, based on scaled
// height
2003-07-28 01:44:38 +00:00
// just use 'feet_x' as centre
_textX = obMega.getFeetX();
2003-07-28 01:44:38 +00:00
// 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
2003-09-20 12:43:52 +00:00
// x-coord + half of width
_textX = cdt_entry.x + frame_head.width / 2;
_textY = cdt_entry.y;
}
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(_animId);
2003-07-28 01:44:38 +00:00
// Leave space above their head
_textY -= GAP_ABOVE_HEAD;
// Adjust the text coords for RDSPR_DISPLAYALIGN
2003-07-28 01:44:38 +00:00
ScreenInfo *screenInfo = _vm->_screen->getScreenInfo();
_textX -= screenInfo->scroll_offset_x;
_textY -= screenInfo->scroll_offset_y;
2003-07-28 01:44:38 +00:00
}
/**
* 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.
*/
2003-07-28 01:44:38 +00:00
void Logic::formText(int32 *params) {
2003-09-20 12:43:52 +00:00
// 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
2003-07-28 01:44:38 +00:00
// There should always be a text line, as all text is derived from it.
// If there is none, that's bad...
2003-07-28 01:44:38 +00:00
if (!params[S_TEXT]) {
warning("No text line for speech wav %d", params[S_WAV]);
return;
}
2003-09-20 12:43:52 +00:00
ObjectSpeech obSpeech(decodePtr(params[S_OB_SPEECH]));
2003-07-28 01:44:38 +00:00
// Establish the max width allowed for this text sprite.
uint32 textWidth = obSpeech.getWidth();
if (!textWidth)
textWidth = 400;
2003-07-28 01:44:38 +00:00
// Pull out the text line, and make the sprite and text block
2003-07-28 01:44:38 +00:00
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);
2003-07-28 01:44:38 +00:00
// 'text + 2' to skip the first 2 bytes which form the line reference
// number
2003-07-28 01:44:38 +00:00
_speechTextBlocNo = _vm->_fontRenderer->buildNewBloc(
text + 2, _textX, _textY,
textWidth, obSpeech.getPen(),
RDSPR_TRANS | RDSPR_DISPLAYALIGN,
_vm->_speechFontId, POSITION_AT_CENTRE_OF_BASE);
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(text_res);
2003-07-28 01:44:38 +00:00
// Set speech duration, in case not using a wav.
_speechTime = strlen((char *)text) + 30;
2003-07-28 01:44:38 +00:00
}
/**
* 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.
*/
2003-07-28 01:44:38 +00:00
bool Logic::wantSpeechForLine(uint32 wavId) {
2003-09-20 12:43:52 +00:00
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;
2003-07-28 01:44:38 +00:00
}
}
2003-10-04 00:52:27 +00:00
} // End of namespace Sword2