1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 
26 #include "common/file.h"
27 #include "common/textconsole.h"
28 
29 #include "sword2/sword2.h"
30 #include "sword2/defs.h"
31 #include "sword2/header.h"
32 #include "sword2/console.h"
33 #include "sword2/logic.h"
34 #include "sword2/maketext.h"
35 #include "sword2/object.h"
36 #include "sword2/resman.h"
37 #include "sword2/screen.h"
38 
39 namespace Sword2 {
40 
41 // To request the status of a target, we run its 4th script, get-speech-state.
42 // This will cause RESULT to be set to either 1 (target is waiting) or 0
43 // (target is busy).
44 
45 // Distance kept above talking sprite
46 #define GAP_ABOVE_HEAD 20
47 
48 enum {
49 	S_OB_GRAPHIC	= 0,
50 	S_OB_SPEECH	= 1,
51 	S_OB_LOGIC	= 2,
52 	S_OB_MEGA	= 3,
53 
54 	S_TEXT		= 4,
55 	S_WAV		= 5,
56 	S_ANIM		= 6,
57 	S_DIR_TABLE	= 7,
58 	S_ANIM_MODE	= 8
59 };
60 
61 /**
62  * Sets _textX and _textY for position of text sprite. Note that _textX is
63  * also used to calculate speech pan.
64  */
65 
locateTalker(int32 * params)66 void Logic::locateTalker(int32 *params) {
67 	// params:	0 pointer to ob_graphic
68 	//		1 pointer to ob_speech
69 	//		2 pointer to ob_logic
70 	//		3 pointer to ob_mega
71 	//		4 encoded text number
72 	//		5 wav res id
73 	//		6 anim res id
74 	//		7 pointer to anim table
75 	//		8 animation mode	0 lip synced,
76 	//					1 just straight animation
77 
78 	if (!_animId) {
79 		// There is no animation. Assume it's voice-over text, and put
80 		// it at the bottom of the screen.
81 
82 		_textX = 320;
83 		_textY = 400;
84 		return;
85 	}
86 
87 	byte *file = _vm->_resman->openResource(_animId);
88 
89 	// '0' means 1st frame
90 
91 	CdtEntry cdt_entry;
92 	FrameHeader frame_head;
93 
94 	cdt_entry.read(_vm->fetchCdtEntry(file, 0));
95 	frame_head.read(_vm->fetchFrameHeader(file, 0));
96 
97 	// Note: This part of the code is quite similar to registerFrame().
98 
99 	if (cdt_entry.frameType & FRAME_OFFSET) {
100 		// The frame has offsets, i.e. it's a scalable mega frame
101 		ObjectMega obMega(decodePtr(params[S_OB_MEGA]));
102 
103 		uint16 scale = obMega.calcScale();
104 
105 		// Calc suitable center point above the head, based on scaled
106 		// height
107 
108 		// just use 'feet_x' as center
109 		_textX = obMega.getFeetX();
110 
111 		// Add scaled y-offset to feet_y coord to get top of sprite
112 		_textY = obMega.getFeetY() + (cdt_entry.y * scale) / 256;
113 	} else {
114 		// It's a non-scaling anim - calc suitable center point above
115 		// the head, based on scaled width
116 
117 		// x-coord + half of width
118 		_textX = cdt_entry.x + frame_head.width / 2;
119 		_textY = cdt_entry.y;
120 	}
121 
122 	_vm->_resman->closeResource(_animId);
123 
124 	// Leave space above their head
125 	_textY -= GAP_ABOVE_HEAD;
126 
127 	// Adjust the text coords for RDSPR_DISPLAYALIGN
128 
129 	ScreenInfo *screenInfo = _vm->_screen->getScreenInfo();
130 
131 	_textX -= screenInfo->scroll_offset_x;
132 	_textY -= screenInfo->scroll_offset_y;
133 }
134 
135 /**
136  * This function is called the first time to build the text, if we need one. If
137  * If necessary it also brings in the wav and sets up the animation.
138  *
139  * If there is an animation it can be repeating lip-sync or run-once.
140  *
141  * If there is no wav, then the text comes up instead. There can be any
142  * combination of text/wav playing.
143  */
144 
formText(int32 * params)145 void Logic::formText(int32 *params) {
146 	// params	0 pointer to ob_graphic
147 	//		1 pointer to ob_speech
148 	//		2 pointer to ob_logic
149 	//		3 pointer to ob_mega
150 	//		4 encoded text number
151 	//		5 wav res id
152 	//		6 anim res id
153 	//		7 pointer to anim table
154 	//		8 animation mode	0 lip synced,
155 	//					1 just straight animation
156 
157 	// There should always be a text line, as all text is derived from it.
158 	// If there is none, that's bad...
159 
160 	if (!params[S_TEXT]) {
161 		warning("No text line for speech wav %d", params[S_WAV]);
162 		return;
163 	}
164 
165 	ObjectSpeech obSpeech(decodePtr(params[S_OB_SPEECH]));
166 
167 	// Establish the max width allowed for this text sprite.
168 	uint32 textWidth = obSpeech.getWidth();
169 
170 	if (!textWidth)
171 		textWidth = 400;
172 
173 	// Pull out the text line, and make the sprite and text block
174 
175 	uint32 text_res = params[S_TEXT] / SIZE;
176 	uint32 local_text = params[S_TEXT] & 0xffff;
177 	byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);
178 
179 	// 'text + 2' to skip the first 2 bytes which form the line reference
180 	// number
181 
182 	_speechTextBlocNo = _vm->_fontRenderer->buildNewBloc(
183 		text + 2, _textX, _textY,
184 		textWidth, obSpeech.getPen(),
185 		RDSPR_TRANS | RDSPR_DISPLAYALIGN,
186 		_vm->_speechFontId, POSITION_AT_CENTER_OF_BASE);
187 
188 	_vm->_resman->closeResource(text_res);
189 
190 	// Set speech duration, in case not using a wav.
191 	_speechTime = strlen((char *)text) + 30;
192 }
193 
194 /**
195  * There are some hard-coded cases where speech is used to illustrate a sound
196  * effect. In this case there is no sound associated with the speech itself.
197  */
198 
wantSpeechForLine(uint32 wavId)199 bool Logic::wantSpeechForLine(uint32 wavId) {
200 	switch (wavId) {
201 	case 1328:	// AttendantSpeech
202 			//	SFX(Phone71);
203 			//	FX <Telephone rings>
204 	case 2059:	// PabloSpeech
205 			//	SFX (2059);
206 			//	FX <Sound of sporadic gunfire from below>
207 	case 4082:	// DuaneSpeech
208 			//	SFX (4082);
209 			//	FX <Pffffffffffft! Frp. (Unimpressive, flatulent noise.)>
210 	case 4214:	// cat_52
211 			//	SFX (4214);
212 			//	4214FXMeow!
213 	case 4568:	// trapdoor_13
214 			//	SFX (4568);
215 			//	4568fx<door slamming>
216 	case 4913:	// LobineauSpeech
217 			//	SFX (tone2);
218 			//	FX <Lobineau hangs up>
219 	case 5120:	// bush_66
220 			//	SFX (5120);
221 			//	5120FX<loud buzzing>
222 	case 528:	// PresidentaSpeech
223 			//	SFX (528);
224 			//	FX <Nearby Crash of Collapsing Masonry>
225 	case 920:	// Zombie Island forest maze (bird)
226 	case 923:	// Zombie Island forest maze (monkey)
227 	case 926:	// Zombie Island forest maze (zombie)
228 		// Don't want speech for these lines!
229 		return false;
230 	default:
231 		// Ok for all other lines
232 		return true;
233 	}
234 }
235 
236 } // End of namespace Sword2
237