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 "xeen/dialogs/dialogs_char_info.h"
24 #include "xeen/dialogs/dialogs_create_char.h"
25 #include "xeen/dialogs/dialogs_party.h"
26 #include "xeen/dialogs/dialogs_input.h"
27 #include "xeen/dialogs/dialogs_query.h"
28 #include "xeen/character.h"
29 #include "xeen/events.h"
30 #include "xeen/party.h"
31 #include "xeen/xeen.h"
32
33 namespace Xeen {
34
PartyDialog(XeenEngine * vm)35 PartyDialog::PartyDialog(XeenEngine *vm) : ButtonContainer(vm),
36 PartyDrawer(vm), _vm(vm) {
37 initDrawStructs();
38 }
39
show(XeenEngine * vm)40 void PartyDialog::show(XeenEngine *vm) {
41 PartyDialog *dlg = new PartyDialog(vm);
42 dlg->execute();
43 delete dlg;
44 }
45
execute()46 void PartyDialog::execute() {
47 EventsManager &events = *_vm->_events;
48 FileManager &files = *_vm->_files;
49 Interface &intf = *_vm->_interface;
50 Party &party = *_vm->_party;
51 Screen &screen = *_vm->_screen;
52 Sound &sound = *_vm->_sound;
53 Windows &windows = *_vm->_windows;
54 bool modeFlag = false;
55 int startingChar = 0;
56
57 sound.playSong(files._ccNum ? "newbrigh.m" : "inn.m");
58 loadButtons();
59 setupBackground();
60
61 while (!_vm->shouldExit()) {
62 _vm->_mode = MODE_INTERACTIVE;
63
64 // Build up a list of available characters in the Roster that are on the
65 // same side of Xeen as the player is currently on
66 loadCharacters();
67
68 Window &w = windows[11];
69 w.open();
70 setupFaces(startingChar, false);
71 w.writeString(Common::String::format(Res.PARTY_DIALOG_TEXT, _partyDetails.c_str()));
72 w.drawList(&_faceDrawStructs[0], 4);
73
74 _uiSprites.draw(w, 0, Common::Point(16, 100));
75 _uiSprites.draw(w, 2, Common::Point(52, 100));
76 _uiSprites.draw(w, 4, Common::Point(87, 100));
77 _uiSprites.draw(w, 6, Common::Point(122, 100));
78 _uiSprites.draw(w, 8, Common::Point(157, 100));
79 _uiSprites.draw(w, 10, Common::Point(192, 100));
80 if (g_vm->getGameID() == GType_Swords)
81 Res._logoSprites.draw(1, 0, Common::Point(232, 9));
82
83 screen.loadPalette("mm4.pal");
84
85 if (modeFlag) {
86 windows[0].update();
87 events.setCursor(0);
88 screen.fadeIn();
89 } else {
90 if (_vm->getGameID() == GType_DarkSide) {
91 screen.fadeOut();
92 windows[0].update();
93 }
94
95 doScroll(false, false);
96 events.setCursor(0);
97
98 if (_vm->getGameID() == GType_DarkSide) {
99 screen.fadeIn();
100 }
101 }
102
103 bool breakFlag = false;
104 while (!_vm->shouldExit() && !breakFlag) {
105 do {
106 events.pollEventsAndWait();
107 checkEvents(_vm);
108 } while (!_vm->shouldExit() && !_buttonValue);
109 if (Common::KEYCODE_F1 == _buttonValue ||
110 Common::KEYCODE_F2 == _buttonValue ||
111 Common::KEYCODE_F3 == _buttonValue ||
112 Common::KEYCODE_F4 == _buttonValue ||
113 Common::KEYCODE_F5 == _buttonValue ||
114 Common::KEYCODE_F6 == _buttonValue) {
115 // Show character info
116 _buttonValue -= Common::KEYCODE_F1;
117 if (_buttonValue < (int)party._activeParty.size())
118 CharacterInfo::show(_vm, _buttonValue);
119 } else if (Common::KEYCODE_1 == _buttonValue ||
120 Common::KEYCODE_2 == _buttonValue ||
121 Common::KEYCODE_3 == _buttonValue ||
122 Common::KEYCODE_4 == _buttonValue) {
123 _buttonValue -= Common::KEYCODE_1 - 7;
124 if ((_buttonValue - 7 + startingChar) < (int)_charList.size()) {
125 // Check if the selected character is already in the party
126 uint idx = 0;
127 for (; idx < party._activeParty.size(); ++idx) {
128 if (_charList[_buttonValue - 7 + startingChar] ==
129 party._activeParty[idx]._rosterId)
130 break;
131 }
132
133 // Only add the character if they're not already in the party
134 if (idx == party._activeParty.size()) {
135 if (party._activeParty.size() == MAX_ACTIVE_PARTY) {
136 sound.playFX(21);
137 ErrorScroll::show(_vm, Res.YOUR_PARTY_IS_FULL);
138 } else {
139 // Add the character to the active party
140 party._activeParty.push_back(party._roster[_charList[_buttonValue - 7 + startingChar]]);
141 startingCharChanged(startingChar);
142 }
143 }
144 }
145
146 } else if (Common::KEYCODE_UP == _buttonValue ||
147 Common::KEYCODE_KP8 == _buttonValue) {
148 // Up arrow
149 if (startingChar > 0) {
150 startingChar -= 4;
151 startingCharChanged(startingChar);
152 }
153
154 } else if (Common::KEYCODE_DOWN == _buttonValue ||
155 Common::KEYCODE_KP2 == _buttonValue) {
156 // Down arrow
157 if (startingChar < ((int)_charList.size() - 4)) {
158 startingChar += 4;
159 startingCharChanged(startingChar);
160 }
161
162 } else if (Res.KeyConstants.DialogsParty.KEY_EXIT == _buttonValue ||
163 Common::KEYCODE_ESCAPE == _buttonValue ||
164 Common::KEYCODE_SPACE == _buttonValue) {
165 if (party._activeParty.size() == 0) {
166 ErrorScroll::show(_vm, Res.NO_ONE_TO_ADVENTURE_WITH);
167 } else {
168 if (_vm->_mode != MODE_STARTUP) {
169 for (int idx = OBSCURITY_NONE; idx >= OBSCURITY_BLACK; --idx) {
170 events.updateGameCounter();
171 intf.obscureScene((Obscurity)idx);
172 w.update();
173
174 while (events.timeElapsed() < 1)
175 events.pollEventsAndWait();
176 }
177 }
178
179 w.close();
180 party._mazeId = party._priorMazeId;
181
182 party.copyPartyToRoster();
183 //_vm->_saves->writeCharFile();
184 return;
185 }
186
187 } else if (Res.KeyConstants.DialogsParty.KEY_CREATE == _buttonValue) {
188 // Create
189 if (_charList.size() == XEEN_TOTAL_CHARACTERS) {
190 ErrorScroll::show(_vm, Res.YOUR_ROSTER_IS_FULL);
191 } else {
192 // Save Background
193 Graphics::ManagedSurface savedBg;
194 savedBg.copyFrom(screen);
195
196 screen.fadeOut();
197 w.close();
198
199 // Show the create character dialog
200 CreateCharacterDialog::show(_vm);
201
202 party.copyPartyToRoster();
203 //_vm->_saves->writeCharFile();
204
205 // Restore Background
206 screen.fadeOut();
207 screen.blitFrom(savedBg);
208 windows[0].update();
209
210 modeFlag = true;
211 breakFlag = true;
212 }
213
214 } else if (Res.KeyConstants.DialogsParty.KEY_DELETE == _buttonValue) {
215 // Delete character
216 if (_charList.size() > 0) {
217 int charButtonValue = selectCharacter(true, startingChar);
218 if (charButtonValue != 0) {
219 int charIndex = charButtonValue - Common::KEYCODE_1 + startingChar;
220 Character &c = party._roster[_charList[charIndex]];
221 if (c.hasSlayerSword()) {
222 ErrorScroll::show(_vm, Res.HAS_SLAYER_SWORD);
223 } else {
224 Common::String msg = Common::String::format(Res.SURE_TO_DELETE_CHAR,
225 c._name.c_str(), Res.CLASS_NAMES[c._class]);
226 if (Confirm::show(_vm, msg)) {
227 // If the character is in the party, remove it
228 for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
229 if (party._activeParty[idx]._rosterId == c._rosterId) {
230 party._activeParty.remove_at(idx);
231 break;
232 }
233 }
234
235 // Empty the character in the roster
236 c.clear();
237
238 loadCharacters();
239 startingChar = 0;
240 startingCharChanged(startingChar);
241 }
242 }
243 }
244 }
245
246 } else if (Res.KeyConstants.DialogsParty.KEY_REMOVE == _buttonValue) {
247 // Remove character
248 if (party._activeParty.size() > 0) {
249 int charButtonValue = selectCharacter(false, startingChar);
250 if (charButtonValue != 0) {
251 party.copyPartyToRoster();
252 party._activeParty.remove_at(charButtonValue - Common::KEYCODE_F1);
253 }
254 startingCharChanged(startingChar);
255 }
256 }
257 }
258 }
259 }
260
loadCharacters()261 void PartyDialog::loadCharacters() {
262 Map &map = *_vm->_map;
263 Party &party = *_vm->_party;
264
265 _charList.clear();
266 for (int i = 0; i < XEEN_TOTAL_CHARACTERS; ++i) {
267 Character &player = party._roster[i];
268 if (player._name.empty() || player._xeenSide != map._loadCcNum)
269 continue;
270
271 _charList.push_back(i);
272 }
273 }
274
loadButtons()275 void PartyDialog::loadButtons() {
276 _uiSprites.load("inn.icn");
277 addButton(Common::Rect(16, 100, 40, 120), Common::KEYCODE_UP, &_uiSprites);
278 addButton(Common::Rect(52, 100, 76, 120), Common::KEYCODE_DOWN, &_uiSprites);
279
280 addButton(Common::Rect(87, 100, 111, 120), Res.KeyConstants.DialogsParty.KEY_DELETE, &_uiSprites);
281 addButton(Common::Rect(122, 100, 146, 120), Res.KeyConstants.DialogsParty.KEY_REMOVE, &_uiSprites);
282 addButton(Common::Rect(157, 100, 181, 120), Res.KeyConstants.DialogsParty.KEY_CREATE, &_uiSprites);
283 addButton(Common::Rect(192, 100, 216, 120), Res.KeyConstants.DialogsParty.KEY_EXIT, &_uiSprites);
284
285 addButton(Common::Rect(0, 0, 0, 0), Common::KEYCODE_ESCAPE);
286 }
287
initDrawStructs()288 void PartyDialog::initDrawStructs() {
289 _faceDrawStructs[0] = DrawStruct(0, 0, 0);
290 _faceDrawStructs[1] = DrawStruct(0, 101, 0);
291 _faceDrawStructs[2] = DrawStruct(0, 0, 43);
292 _faceDrawStructs[3] = DrawStruct(0, 101, 43);
293 }
294
setupBackground()295 void PartyDialog::setupBackground() {
296 _vm->_screen->loadBackground("back.raw");
297 _vm->_interface->assembleBorder();
298 }
299
setupFaces(int firstDisplayChar,bool updateFlag)300 void PartyDialog::setupFaces(int firstDisplayChar, bool updateFlag) {
301 Party &party = *_vm->_party;
302 Common::String charNames[4];
303 Common::String charRaces[4];
304 Common::String charSex[4];
305 Common::String charClasses[4];
306 int posIndex;
307 int charId;
308
309 // Reset the button areas for the display character images
310 while (_buttons.size() > 7)
311 _buttons.remove_at(7);
312 addButton(Common::Rect(16, 16, 48, 48), Common::KEYCODE_1);
313 addButton(Common::Rect(117, 16, 149, 48), Common::KEYCODE_2);
314 addButton(Common::Rect(59, 59, 91, 91), Common::KEYCODE_3);
315 addButton(Common::Rect(117, 59, 151, 91), Common::KEYCODE_4);
316
317
318 for (posIndex = 0; posIndex < 4; ++posIndex) {
319 charId = (firstDisplayChar + posIndex) >= (int)_charList.size() ? -1 :
320 _charList[firstDisplayChar + posIndex];
321 bool isInParty = party.isInParty(charId);
322
323 if (charId == -1) {
324 while ((int)_buttons.size() >(7 + posIndex))
325 _buttons.remove_at(_buttons.size() - 1);
326 break;
327 }
328
329 Common::Rect &b = _buttons[7 + posIndex]._bounds;
330 b.moveTo((posIndex & 1) ? 117 : 16, b.top);
331 Character &ps = party._roster[_charList[firstDisplayChar + posIndex]];
332 charNames[posIndex] = isInParty ? Res.IN_PARTY : ps._name;
333 charRaces[posIndex] = Res.RACE_NAMES[ps._race];
334 charSex[posIndex] = Res.SEX_NAMES[ps._sex];
335 charClasses[posIndex] = Res.CLASS_NAMES[ps._class];
336 }
337
338 drawParty(updateFlag);
339
340 // Set up the sprite set to use for each face
341 for (posIndex = 0; posIndex < 4; ++posIndex) {
342 if ((firstDisplayChar + posIndex) >= (int)_charList.size())
343 _faceDrawStructs[posIndex]._sprites = nullptr;
344 else
345 _faceDrawStructs[posIndex]._sprites = party._roster[
346 _charList[firstDisplayChar + posIndex]]._faceSprites;
347 }
348
349 _partyDetails = Common::String::format(Res.PARTY_DETAILS,
350 charNames[0].c_str(), charRaces[0].c_str(), charSex[0].c_str(), charClasses[0].c_str(),
351 charNames[1].c_str(), charRaces[1].c_str(), charSex[1].c_str(), charClasses[1].c_str(),
352 charNames[2].c_str(), charRaces[2].c_str(), charSex[2].c_str(), charClasses[2].c_str(),
353 charNames[3].c_str(), charRaces[3].c_str(), charSex[3].c_str(), charClasses[3].c_str()
354 );
355 }
356
startingCharChanged(int firstDisplayChar)357 void PartyDialog::startingCharChanged(int firstDisplayChar) {
358 Windows &windows = *_vm->_windows;
359 Window &w = windows[11];
360
361 setupFaces(firstDisplayChar, true);
362 w.writeString(Common::String::format(Res.PARTY_DIALOG_TEXT, _partyDetails.c_str()));
363 w.drawList(_faceDrawStructs, 4);
364
365 _uiSprites.draw(w, 0, Common::Point(16, 100));
366 _uiSprites.draw(w, 2, Common::Point(52, 100));
367 _uiSprites.draw(w, 4, Common::Point(87, 100));
368 _uiSprites.draw(w, 6, Common::Point(122, 100));
369 _uiSprites.draw(w, 8, Common::Point(157, 100));
370 _uiSprites.draw(w, 10, Common::Point(192, 100));
371
372 w.update();
373 }
374
selectCharacter(bool isDelete,int firstDisplayChar)375 int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) {
376 EventsManager &events = *_vm->_events;
377 Party &party = *_vm->_party;
378 Windows &windows = *_vm->_windows;
379 Window &w = windows[28];
380
381 SpriteResource iconSprites;
382 iconSprites.load("esc.icn");
383
384 w.setBounds(Common::Rect(50, isDelete ? 112 : 76, 266, isDelete ? 148 : 112));
385 w.open();
386 w.writeString(Common::String::format(Res.REMOVE_OR_DELETE_WHICH,
387 Res.REMOVE_DELETE[isDelete ? 1 : 0]));
388 iconSprites.draw(w, 0, Common::Point(225, isDelete ? 120 : 84));
389 w.update();
390
391 saveButtons();
392 addButton(Common::Rect(225, isDelete ? 120 : 84, 249, isDelete ? 140 : 104),
393 Common::KEYCODE_ESCAPE, &iconSprites);
394 addButton(Common::Rect(16, 16, 48, 48), Common::KEYCODE_1);
395 addButton(Common::Rect(117, 16, 149, 48), Common::KEYCODE_2);
396 addButton(Common::Rect(16, 59, 48, 91), Common::KEYCODE_3);
397 addButton(Common::Rect(117, 59, 149, 91), Common::KEYCODE_4);
398 addPartyButtons(_vm);
399
400 int result = -1, v;
401 while (!_vm->shouldExit() && result == -1) {
402 _buttonValue = 0;
403 while (!_vm->shouldExit() && !_buttonValue) {
404 events.pollEventsAndWait();
405 checkEvents(_vm);
406 }
407
408 switch (_buttonValue) {
409 case Common::KEYCODE_ESCAPE:
410 result = 0;
411 break;
412
413 case Common::KEYCODE_F1:
414 case Common::KEYCODE_F2:
415 case Common::KEYCODE_F3:
416 case Common::KEYCODE_F4:
417 case Common::KEYCODE_F5:
418 case Common::KEYCODE_F6:
419 if (!isDelete) {
420 v = _buttonValue - Common::KEYCODE_F1;
421 if (v < (int)party._activeParty.size())
422 result = _buttonValue;
423 }
424 break;
425
426 case Common::KEYCODE_1:
427 case Common::KEYCODE_2:
428 case Common::KEYCODE_3:
429 case Common::KEYCODE_4:
430 if (isDelete) {
431 v = _buttonValue - Common::KEYCODE_1;
432 if ((firstDisplayChar + v) < (int)_charList.size())
433 result = _buttonValue;
434 }
435 break;
436
437 default:
438 break;
439 }
440 }
441
442 w.close();
443 restoreButtons();
444 return result == -1 ? 0 : result;
445 }
446
447 } // End of namespace Xeen
448