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  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "sherlock/scalpel/scalpel_inventory.h"
24 #include "sherlock/scalpel/scalpel_fixed_text.h"
25 #include "sherlock/scalpel/scalpel_screen.h"
26 #include "sherlock/scalpel/scalpel_user_interface.h"
27 #include "sherlock/scalpel/scalpel.h"
28 
29 namespace Sherlock {
30 
31 namespace Scalpel {
32 
ScalpelInventory(SherlockEngine * vm)33 ScalpelInventory::ScalpelInventory(SherlockEngine *vm) : Inventory(vm) {
34 	_invShapes.resize(6);
35 
36 	_fixedTextExit = FIXED(Inventory_Exit);
37 	_fixedTextLook = FIXED(Inventory_Look);
38 	_fixedTextUse  = FIXED(Inventory_Use);
39 	_fixedTextGive = FIXED(Inventory_Give);
40 
41 	_hotkeyExit = toupper(_fixedTextExit[0]);
42 	_hotkeyLook = toupper(_fixedTextLook[0]);
43 	_hotkeyUse = toupper(_fixedTextUse[0]);
44 	_hotkeyGive = toupper(_fixedTextGive[0]);
45 
46 	_hotkeysIndexed[0] = _hotkeyExit;
47 	_hotkeysIndexed[1] = _hotkeyLook;
48 	_hotkeysIndexed[2] = _hotkeyUse;
49 	_hotkeysIndexed[3] = _hotkeyGive;
50 	_hotkeysIndexed[4] = '-';
51 	_hotkeysIndexed[5] = '+';
52 	_hotkeysIndexed[6] = ',';
53 	_hotkeysIndexed[7] = '.';
54 }
55 
~ScalpelInventory()56 ScalpelInventory::~ScalpelInventory() {
57 }
58 
identifyUserButton(int key)59 int ScalpelInventory::identifyUserButton(int key) {
60 	for (uint16 hotkeyNr = 0; hotkeyNr < sizeof(_hotkeysIndexed); hotkeyNr++) {
61 		if (key == _hotkeysIndexed[hotkeyNr])
62 			return hotkeyNr;
63 	}
64 	return -1;
65 }
66 
drawInventory(InvNewMode mode)67 void ScalpelInventory::drawInventory(InvNewMode mode) {
68 	ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
69 	UserInterface &ui = *_vm->_ui;
70 	InvNewMode tempMode = mode;
71 
72 	loadInv();
73 
74 	if (mode == INVENTORY_DONT_DISPLAY) {
75 		screen.activateBackBuffer2();
76 	}
77 
78 	// Draw the window background
79 	Surface &bb = *screen.getBackBuffer();
80 	bb.fillRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y1 + 10), BORDER_COLOR);
81 	bb.fillRect(Common::Rect(0, CONTROLS_Y1 + 10, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
82 	bb.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y1 + 10,
83 		SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
84 	bb.fillRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH,
85 		SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
86 	bb.fillRect(Common::Rect(2, CONTROLS_Y1 + 10, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT - 1),
87 		INV_BACKGROUND);
88 
89 	// Draw the buttons
90 	screen.makeButton(Common::Rect(INVENTORY_POINTS[0][0], CONTROLS_Y1, INVENTORY_POINTS[0][1],
91 		CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2], _fixedTextExit);
92 	screen.makeButton(Common::Rect(INVENTORY_POINTS[1][0], CONTROLS_Y1, INVENTORY_POINTS[1][1],
93 		CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2], _fixedTextLook);
94 	screen.makeButton(Common::Rect(INVENTORY_POINTS[2][0], CONTROLS_Y1, INVENTORY_POINTS[2][1],
95 		CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2], _fixedTextUse);
96 	screen.makeButton(Common::Rect(INVENTORY_POINTS[3][0], CONTROLS_Y1, INVENTORY_POINTS[3][1],
97 		CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2], _fixedTextGive);
98 	screen.makeButton(Common::Rect(INVENTORY_POINTS[4][0], CONTROLS_Y1, INVENTORY_POINTS[4][1],
99 		CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2] + 8, "^^", false); // 2 arrows pointing to the left
100 	screen.makeButton(Common::Rect(INVENTORY_POINTS[5][0], CONTROLS_Y1, INVENTORY_POINTS[5][1],
101 		CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2] + 4, "^", false); // 1 arrow pointing to the left
102 	screen.makeButton(Common::Rect(INVENTORY_POINTS[6][0], CONTROLS_Y1, INVENTORY_POINTS[6][1],
103 		CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2] + 4, "_", false); // 1 arrow pointing to the right
104 	screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1],
105 		CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2] + 8, "__", false); // 2 arrows pointing to the right
106 
107 	if (tempMode == INVENTORY_DONT_DISPLAY)
108 		mode = LOOK_INVENTORY_MODE;
109 	_invMode = (InvMode)((int)mode);
110 
111 	if (mode != PLAIN_INVENTORY) {
112 		assert((uint)mode < sizeof(_hotkeysIndexed));
113 		ui._oldKey = _hotkeysIndexed[mode];
114 	} else {
115 		ui._oldKey = -1;
116 	}
117 
118 	invCommands(0);
119 	putInv(SLAM_DONT_DISPLAY);
120 
121 	if (tempMode != INVENTORY_DONT_DISPLAY) {
122 		if (!ui._slideWindows) {
123 			screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
124 		} else {
125 			ui.summonWindow(false, CONTROLS_Y1);
126 		}
127 
128 		ui._windowOpen = true;
129 	} else {
130 		// Reset the screen back buffer to the first buffer now that drawing is done
131 		screen.activateBackBuffer1();
132 	}
133 
134 	assert(IS_SERRATED_SCALPEL);
135 	((ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
136 }
137 
invCommands(bool slamIt)138 void ScalpelInventory::invCommands(bool slamIt) {
139 	ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
140 	UserInterface &ui = *_vm->_ui;
141 
142 	if (slamIt) {
143 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
144 			_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
145 			true, _fixedTextExit);
146 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
147 			_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
148 			true, _fixedTextLook);
149 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
150 			_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
151 			true, _fixedTextUse);
152 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
153 			_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
154 			true, _fixedTextGive);
155 		screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
156 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
157 			"^^"); // 2 arrows pointing to the left
158 		screen.print(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
159 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
160 			"^"); // 2 arrows pointing to the left
161 		screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
162 			(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
163 			"_"); // 1 arrow pointing to the right
164 		screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
165 			(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
166 			"__"); // 2 arrows pointing to the right
167 		if (_invMode != INVMODE_LOOK)
168 			ui.clearInfo();
169 	} else {
170 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
171 			_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
172 			false, _fixedTextExit);
173 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
174 			_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
175 			false, _fixedTextLook);
176 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
177 			_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
178 			false, _fixedTextUse);
179 		screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
180 			_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
181 			false, _fixedTextGive);
182 		screen.gPrint(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1),
183 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
184 			"^^"); // 2 arrows pointing to the left
185 		screen.gPrint(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1),
186 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
187 			"^"); // 1 arrow pointing to the left
188 		screen.gPrint(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1),
189 			(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
190 			"_"); // 1 arrow pointing to the right
191 		screen.gPrint(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1),
192 			(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
193 			"__"); // 2 arrows pointing to the right
194 	}
195 }
196 
highlight(int index,byte color)197 void ScalpelInventory::highlight(int index, byte color) {
198 	Screen &screen = *_vm->_screen;
199 	Surface &bb = *screen.getBackBuffer();
200 	int slot = index - _invIndex;
201 	ImageFrame &frame = (*_invShapes[slot])[0];
202 
203 	bb.fillRect(Common::Rect(8 + slot * 52, 165, (slot + 1) * 52, 194), color);
204 	bb.SHtransBlitFrom(frame, Common::Point(6 + slot * 52 + ((47 - frame._width) / 2),
205 		163 + ((33 - frame._height) / 2)));
206 	screen.slamArea(8 + slot * 52, 165, 44, 30);
207 }
208 
refreshInv()209 void ScalpelInventory::refreshInv() {
210 	Screen &screen = *_vm->_screen;
211 	Talk &talk = *_vm->_talk;
212 	ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
213 
214 	ui._invLookFlag = true;
215 	freeInv();
216 
217 	ui._infoFlag = true;
218 	ui.clearInfo();
219 
220 	screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
221 		Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
222 	ui.examine();
223 
224 	if (!talk._talkToAbort) {
225 		screen._backBuffer2.SHblitFrom((*ui._controlPanel)[0], Common::Point(0, CONTROLS_Y));
226 		loadInv();
227 	}
228 }
229 
putInv(InvSlamMode slamIt)230 void ScalpelInventory::putInv(InvSlamMode slamIt) {
231 	ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
232 	UserInterface &ui = *_vm->_ui;
233 
234 	// If an inventory item has disappeared (due to using it or giving it),
235 	// a blank space slot may have appeared. If so, adjust the inventory
236 	if (_invIndex > 0 && _invIndex > (_holdings - (int)_invShapes.size())) {
237 		--_invIndex;
238 		freeGraphics();
239 		loadGraphics();
240 	}
241 
242 	if (slamIt != SLAM_SECONDARY_BUFFER) {
243 		screen.makePanel(Common::Rect(6, 163, 54, 197));
244 		screen.makePanel(Common::Rect(58, 163, 106, 197));
245 		screen.makePanel(Common::Rect(110, 163, 158, 197));
246 		screen.makePanel(Common::Rect(162, 163, 210, 197));
247 		screen.makePanel(Common::Rect(214, 163, 262, 197));
248 		screen.makePanel(Common::Rect(266, 163, 314, 197));
249 	}
250 
251 	// Iterate through displaying up to 6 objects at a time
252 	for (int idx = _invIndex; idx < _holdings && (idx - _invIndex) < (int)_invShapes.size(); ++idx) {
253 		int itemNum = idx - _invIndex;
254 		Surface &bb = (slamIt == SLAM_SECONDARY_BUFFER) ? screen._backBuffer2 : *screen.getBackBuffer();
255 		Common::Rect r(8 + itemNum * 52, 165, 51 + itemNum * 52, 194);
256 
257 		// Draw the background
258 		if (idx == ui._selector) {
259 			bb.fillRect(r, BUTTON_BACKGROUND);
260 		}
261 		else if (slamIt == SLAM_SECONDARY_BUFFER) {
262 			bb.fillRect(r, BUTTON_MIDDLE);
263 		}
264 
265 		// Draw the item image
266 		ImageFrame &frame = (*_invShapes[itemNum])[0];
267 		bb.SHtransBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2),
268 			163 + ((33 - frame._height) / 2)));
269 	}
270 
271 	if (slamIt == SLAM_DISPLAY)
272 		screen.slamArea(6, 163, 308, 34);
273 
274 	if (slamIt != SLAM_SECONDARY_BUFFER)
275 		ui.clearInfo();
276 
277 	if (slamIt == 0) {
278 		invCommands(0);
279 	}
280 	else if (slamIt == SLAM_SECONDARY_BUFFER) {
281 		screen.activateBackBuffer2();
282 		invCommands(0);
283 		screen.activateBackBuffer1();
284 	}
285 }
286 
loadInv()287 void ScalpelInventory::loadInv() {
288 	// Exit if the inventory names are already loaded
289 	if (_names.size() > 0)
290 		return;
291 
292 	// Load the inventory names
293 	Common::SeekableReadStream *stream = _vm->_res->load("invent.txt");
294 
295 	int streamSize = stream->size();
296 	while (stream->pos() < streamSize) {
297 		Common::String name;
298 		char c;
299 		while ((c = stream->readByte()) != 0)
300 			name += c;
301 
302 		_names.push_back(name);
303 	}
304 
305 	delete stream;
306 
307 	loadGraphics();
308 }
309 
310 } // End of namespace Scalpel
311 
312 } // End of namespace Sherlock
313