[Scummvm-git-logs] scummvm master -> 1d69120112e16a74a9d101a0d4d9de04196d29de

dreammaster dreammaster at scummvm.org
Sun Feb 18 22:19:29 CET 2018


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
1d69120112 XEEN: Split up code for create character dialog into it's own class


Commit: 1d69120112e16a74a9d101a0d4d9de04196d29de
    https://github.com/scummvm/scummvm/commit/1d69120112e16a74a9d101a0d4d9de04196d29de
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-02-18T16:19:31-05:00

Commit Message:
XEEN: Split up code for create character dialog into it's own class

Changed paths:
  A engines/xeen/dialogs_create_char.cpp
  A engines/xeen/dialogs_create_char.h
    engines/xeen/dialogs_party.cpp
    engines/xeen/dialogs_party.h
    engines/xeen/module.mk


diff --git a/engines/xeen/dialogs_create_char.cpp b/engines/xeen/dialogs_create_char.cpp
new file mode 100644
index 0000000..5cf3df2
--- /dev/null
+++ b/engines/xeen/dialogs_create_char.cpp
@@ -0,0 +1,658 @@
+/* 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.
+ *
+ * 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.
+ *
+ */
+
+#include "xeen/dialogs_create_char.h"
+#include "xeen/dialogs_input.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void CreateCharacterDialog::show(XeenEngine *vm) {
+	CreateCharacterDialog *dlg = new CreateCharacterDialog(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+CreateCharacterDialog::CreateCharacterDialog(XeenEngine *vm) : ButtonContainer(vm) {
+}
+
+void CreateCharacterDialog::execute() {
+	EventsManager &events = *_vm->_events;
+	Party &party = *_vm->_party;
+	Screen &screen = *_vm->_screen;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[0];
+	SpriteResource dice, icons;
+	Common::Array<int> freeCharList;
+	int classId;
+	int selectedClass = 0;
+	bool hasFadedIn = false;
+	bool restartFlag = true;
+	uint attribs[TOTAL_ATTRIBUTES];
+	bool allowedClasses[TOTAL_CLASSES];
+	Race race = HUMAN;
+	Sex sex = MALE;
+	Common::String msg, details;
+	int charIndex = 0;
+
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_4;
+	dice.load("dice.vga");
+	icons.load("create.icn");
+
+	_dicePos[0] = Common::Point(20, 17);
+	_dicePos[1] = Common::Point(112, 35);
+	_dicePos[2] = Common::Point(61, 50);
+	_diceFrame[0] = 0;
+	_diceFrame[1] = 2;
+	_diceFrame[2] = 4;
+	_diceInc[0] = Common::Point(10, -10);
+	_diceInc[1] = Common::Point(-10, -10);
+	_diceInc[2] = Common::Point(-10, 10);
+
+	// Add buttons
+	saveButtons();
+	addButton(Common::Rect(132, 98, 156, 118), Common::KEYCODE_r, &icons);
+	addButton(Common::Rect(132, 128, 156, 148), Common::KEYCODE_c, &icons);
+	addButton(Common::Rect(132, 158, 156, 178), Common::KEYCODE_ESCAPE, &icons);
+	addButton(Common::Rect(86, 98, 110, 118), Common::KEYCODE_UP, &icons);
+	addButton(Common::Rect(86, 120, 110, 140), Common::KEYCODE_DOWN, &icons);
+	addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_n, nullptr);
+	addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i, nullptr);
+	addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p, nullptr);
+	addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e, nullptr);
+	addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s, nullptr);
+	addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a, nullptr);
+	addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l, nullptr);
+	addButton(Common::Rect(227, 19, 239, 29), 1000, nullptr);
+	addButton(Common::Rect(227, 30, 239, 40), 1001, nullptr);
+	addButton(Common::Rect(227, 41, 239, 51), 1002, nullptr);
+	addButton(Common::Rect(227, 52, 239, 62), 1003, nullptr);
+	addButton(Common::Rect(227, 63, 239, 73), 1004, nullptr);
+	addButton(Common::Rect(227, 74, 239, 84), 1005, nullptr);
+	addButton(Common::Rect(227, 85, 239, 95), 1006, nullptr);
+	addButton(Common::Rect(227, 96, 239, 106), 1007, nullptr);
+	addButton(Common::Rect(227, 107, 239, 117), 1008, nullptr);
+	addButton(Common::Rect(227, 118, 239, 128), 1009, nullptr);
+
+	// Load the background
+	screen.loadBackground("create.raw");
+	events.setCursor(0);
+
+	while (!_vm->shouldExit()) {
+		classId = -1;
+
+		if (restartFlag) {
+			// Build up list of roster slot indexes that are free
+			freeCharList.clear();
+			for (uint idx = 0; idx < XEEN_TOTAL_CHARACTERS; ++idx) {
+				if (party._roster[idx]._name.empty())
+					freeCharList.push_back(idx);
+			}
+			charIndex = 0;
+			//bool flag9 = true;
+
+			if (freeCharList.size() == XEEN_TOTAL_CHARACTERS)
+				break;
+
+			// Get and race and sex for the given character
+			race = (Race)((freeCharList[charIndex] / 4) % 5);
+			sex = (Sex)(freeCharList[charIndex] & 1);
+
+			// Randomly determine attributes, and which classes they allow
+			throwDice(attribs, allowedClasses);
+
+			// Get the display of the rolled character details
+			selectedClass = newCharDetails(attribs, allowedClasses,
+				race, sex, classId, selectedClass, details);
+			msg = Common::String::format(Res.CREATE_CHAR_DETAILS,
+				details.c_str());
+
+			// Draw the screen
+			icons.draw(w, 10, Common::Point(168, 19));
+			icons.draw(w, 12, Common::Point(168, 43));
+			icons.draw(w, 14, Common::Point(168, 67));
+			icons.draw(w, 16, Common::Point(168, 91));
+			icons.draw(w, 18, Common::Point(168, 115));
+			icons.draw(w, 20, Common::Point(168, 139));
+			icons.draw(w, 22, Common::Point(168, 163));
+			for (int idx = 0; idx < 9; ++idx)
+				icons.draw(w, 24 + idx * 2, Common::Point(227, 19 + 11 * idx));
+
+			for (int idx = 0; idx < 7; ++idx)
+				icons.draw(w, 50 + idx, Common::Point(195, 31 + 24 * idx));
+
+			icons.draw(w, 57, Common::Point(62, 148));
+			icons.draw(w, 58, Common::Point(62, 158));
+			icons.draw(w, 59, Common::Point(62, 168));
+			icons.draw(w, 61, Common::Point(220, 19));
+			icons.draw(w, 64, Common::Point(220, 155));
+			icons.draw(w, 65, Common::Point(220, 170));
+
+			party._roster[freeCharList[charIndex]]._faceSprites->draw(
+				w, 0, Common::Point(27, 102));
+
+			icons.draw(w, 0, Common::Point(132, 98));
+			icons.draw(w, 2, Common::Point(132, 128));
+			icons.draw(w, 4, Common::Point(132, 158));
+			icons.draw(w, 6, Common::Point(86, 98));
+			icons.draw(w, 8, Common::Point(86, 120));
+
+			w.writeString(msg);
+			w.update();
+
+			// Draw the arrow for the selected class, if applicable
+			if (selectedClass != -1)
+				printSelectionArrow(icons, selectedClass);
+
+			// Draw the dice
+			drawDice(dice);
+			if (!hasFadedIn) {
+				screen.fadeIn();
+				hasFadedIn = true;
+			}
+
+			restartFlag = false;
+		}
+
+		// Animate the dice until a user action occurs
+		_buttonValue = 0;
+		while (!_vm->shouldExit() && !_buttonValue)
+			drawDice(dice);
+
+		// Handling for different actions
+		switch (_buttonValue) {
+		case Common::KEYCODE_UP:
+			if (charIndex == 0)
+				continue;
+
+			race = (Race)((freeCharList[charIndex] / 4) % 5);
+			sex = (Sex)(freeCharList[charIndex] & 1);
+			break;
+
+		case Common::KEYCODE_DOWN:
+			if (++charIndex == (int)freeCharList.size()) {
+				--charIndex;
+				continue;
+			} else {
+				race = (Race)((freeCharList[charIndex] / 4) % 5);
+				sex = (Sex)(freeCharList[charIndex] & 1);
+			}
+			break;
+
+		case Common::KEYCODE_PAGEUP:
+			for (int tempClass = selectedClass - 1; tempClass >= 0; --tempClass) {
+				if (allowedClasses[tempClass]) {
+					selectedClass = tempClass;
+					break;
+				}
+			}
+
+			printSelectionArrow(icons, selectedClass);
+			continue;
+
+		case Common::KEYCODE_PAGEDOWN:
+			break;
+
+		case Common::KEYCODE_m:
+		case Common::KEYCODE_i:
+		case Common::KEYCODE_p:
+		case Common::KEYCODE_e:
+		case Common::KEYCODE_s:
+		case Common::KEYCODE_a:
+		case Common::KEYCODE_l: {
+			Attribute srcAttrib, destAttrib;
+			if (_buttonValue == Common::KEYCODE_m)
+				srcAttrib = MIGHT;
+			else if (_buttonValue == Common::KEYCODE_i)
+				srcAttrib = INTELLECT;
+			else if (_buttonValue == Common::KEYCODE_p)
+				srcAttrib = PERSONALITY;
+			else if (_buttonValue == Common::KEYCODE_e)
+				srcAttrib = ENDURANCE;
+			else if (_buttonValue == Common::KEYCODE_s)
+				srcAttrib = SPEED;
+			else if (_buttonValue == Common::KEYCODE_a)
+				srcAttrib = ACCURACY;
+			else
+				srcAttrib = LUCK;
+
+			_vm->_mode = MODE_86;
+			icons.draw(w, srcAttrib * 2 + 11, Common::Point(
+				_buttons[srcAttrib + 5]._bounds.left, _buttons[srcAttrib + 5]._bounds.top));
+			w.update();
+
+			int destAttribVal = exchangeAttribute(srcAttrib + 1);
+			if (destAttribVal) {
+				destAttrib = (Attribute)(destAttribVal - 1);
+				icons.draw(w, destAttrib * 2 + 11, Common::Point(
+					_buttons[destAttrib + 10]._bounds.left,
+					_buttons[destAttrib + 10]._bounds.top));
+				w.update();
+
+				SWAP(attribs[srcAttrib], attribs[destAttrib]);
+				checkClass(attribs, allowedClasses);
+				classId = -1;
+				selectedClass = newCharDetails(attribs, allowedClasses,
+					race, sex, classId, selectedClass, msg);
+			} else {
+				icons.draw(w, srcAttrib * 2 + 10, Common::Point(
+					_buttons[srcAttrib + 5]._bounds.left,
+					_buttons[srcAttrib + 5]._bounds.top));
+				w.update();
+				_vm->_mode = MODE_SLEEPING;
+				continue;
+			}
+			break;
+		}
+
+		case 1000:
+		case 1001:
+		case 1002:
+		case 1003:
+		case 1004:
+		case 1005:
+		case 1006:
+		case 1007:
+		case 1008:
+		case 1009:
+			if (allowedClasses[_buttonValue - 1000]) {
+				selectedClass = classId = _buttonValue - 1000;
+			}
+			break;
+
+		case Common::KEYCODE_c: {
+			_vm->_mode = MODE_FF;
+			bool result = saveCharacter(party._roster[freeCharList[charIndex]],
+				classId, race, sex, attribs);
+			_vm->_mode = MODE_4;
+
+			if (result)
+				restartFlag = true;
+			continue;
+		}
+
+		case Common::KEYCODE_RETURN:
+			classId = selectedClass;
+			break;
+
+		case Common::KEYCODE_SPACE:
+		case Common::KEYCODE_r:
+			// Re-roll the attributes
+			throwDice(attribs, allowedClasses);
+			classId = -1;
+			break;
+
+		default:
+			// For all other keypresses, skip the code below the switch
+			// statement, and go to wait for the next key
+			continue;
+		}
+
+		if (_buttonValue != Common::KEYCODE_PAGEDOWN) {
+			selectedClass = newCharDetails(attribs, allowedClasses,
+				race, sex, classId, selectedClass, msg);
+
+			for (int idx = 0; idx < 7; ++idx)
+				icons.draw(w, 10 + idx * 2, Common::Point(168, 19 + idx * 24));
+			for (int idx = 0; idx < 10; ++idx)
+				icons.draw(w, 24 + idx * 2, Common::Point(227, 19 + idx * 11));
+			for (int idx = 0; idx < 8; ++idx)
+				icons.draw(w, 50 + idx, Common::Point(195, 31 + idx * 24));
+
+			icons.draw(w, 57, Common::Point(62, 148));
+			icons.draw(w, 58, Common::Point(62, 158));
+			icons.draw(w, 59, Common::Point(62, 168));
+			icons.draw(w, 61, Common::Point(220, 19));
+			icons.draw(w, 64, Common::Point(220, 155));
+			icons.draw(w, 65, Common::Point(220, 170));
+
+			party._roster[freeCharList[charIndex]]._faceSprites->draw(w, 0,
+				Common::Point(27, 102));
+
+			icons.draw(w, 0, Common::Point(132, 98));
+			icons.draw(w, 2, Common::Point(132, 128));
+			icons.draw(w, 4, Common::Point(132, 158));
+			icons.draw(w, 6, Common::Point(86, 98));
+			icons.draw(w, 8, Common::Point(86, 120));
+
+			w.writeString(msg);
+			w.update();
+
+			if (selectedClass != -1) {
+				printSelectionArrow(icons, selectedClass);
+				continue;
+			}
+		}
+
+		// Move to next available class, or if the code block above resulted in
+		// selectedClass being -1, move to select the first available class
+		for (int tempClass = selectedClass + 1; tempClass <= CLASS_RANGER; ++tempClass) {
+			if (allowedClasses[tempClass]) {
+				selectedClass = tempClass;
+				break;
+			}
+		}
+
+		printSelectionArrow(icons, selectedClass);
+	} while (!_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
+
+	_vm->_mode = oldMode;
+}
+
+void CreateCharacterDialog::loadButtons() {
+	_icons.load("inn.icn");
+	addButton(Common::Rect(16, 100, 40, 120), Common::KEYCODE_UP, &_icons);
+	addButton(Common::Rect(52, 100, 76, 120), Common::KEYCODE_DOWN, &_icons);
+	addButton(Common::Rect(87, 100, 111, 120), Common::KEYCODE_d, &_icons);
+	addButton(Common::Rect(122, 100, 146, 120), Common::KEYCODE_r, &_icons);
+	addButton(Common::Rect(157, 100, 181, 120), Common::KEYCODE_c, &_icons);
+	addButton(Common::Rect(192, 100, 216, 120), Common::KEYCODE_x, &_icons);
+	addButton(Common::Rect(0, 0, 0, 0), Common::KEYCODE_ESCAPE);
+}
+
+void CreateCharacterDialog::throwDice(uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]) {
+	bool repeat = true;
+	do {
+		// Default all the attributes to zero
+		Common::fill(&attribs[0], &attribs[TOTAL_ATTRIBUTES], 0);
+
+		// Assign random amounts to each attribute
+		for (int idx1 = 0; idx1 < 3; ++idx1) {
+			for (int idx2 = 0; idx2 < TOTAL_ATTRIBUTES; ++idx2) {
+				attribs[idx1] += _vm->getRandomNumber(10, 79) / 10;
+			}
+		}
+
+		// Check which classes are allowed based on the rolled attributes
+		checkClass(attribs, allowedClasses);
+
+		// Only exit if the attributes allow for at least one class
+		for (int idx = 0; idx < TOTAL_CLASSES; ++idx) {
+			if (allowedClasses[idx])
+				repeat = false;
+		}
+	} while (repeat);
+}
+
+void CreateCharacterDialog::checkClass(const uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]) {
+	allowedClasses[CLASS_KNIGHT] = attribs[MIGHT] >= 15;
+	allowedClasses[CLASS_PALADIN] = attribs[MIGHT] >= 13
+		&& attribs[PERSONALITY] >= 13 && attribs[ENDURANCE] >= 13;
+	allowedClasses[CLASS_ARCHER] = attribs[INTELLECT] >= 13 && attribs[ACCURACY] >= 13;
+	allowedClasses[CLASS_CLERIC] = attribs[PERSONALITY] >= 13;
+	allowedClasses[CLASS_SORCERER] = attribs[INTELLECT] >= 13;
+	allowedClasses[CLASS_ROBBER] = attribs[LUCK] >= 13;
+	allowedClasses[CLASS_NINJA] = attribs[SPEED] >= 13 && attribs[ACCURACY] >= 13;
+	allowedClasses[CLASS_BARBARIAN] = attribs[ENDURANCE] >= 15;
+	allowedClasses[CLASS_DRUID] = attribs[INTELLECT] >= 15 && attribs[PERSONALITY] >= 15;
+	allowedClasses[CLASS_RANGER] = attribs[INTELLECT] >= 12 && attribs[PERSONALITY] >= 12
+		&& attribs[ENDURANCE] >= 12 && attribs[SPEED] >= 12;
+}
+
+int CreateCharacterDialog::newCharDetails(const uint attribs[TOTAL_ATTRIBUTES],
+		bool allowedClasses[TOTAL_CLASSES], Race race, Sex sex, int classId,
+		int selectedClass, Common::String &msg) {
+	int foundClass = -1;
+	Common::String skillStr, classStr, raceSkillStr;
+
+	// If a selected class is provided, set the default skill for that class
+	if (classId != -1 && Res.NEW_CHAR_SKILLS[classId] != -1) {
+		const char *skillP = Res.SKILL_NAMES[Res.NEW_CHAR_SKILLS[classId]];
+		skillStr = Common::String(skillP, skillP + Res.NEW_CHAR_SKILLS_LEN[classId]);
+	}
+
+	// If a class is provided, set the class name
+	if (classId != -1) {
+		classStr = Common::String::format("\t062\v168%s", Res.CLASS_NAMES[classId]);
+	}
+
+	// Set up default skill for the race, if any
+	if (Res.NEW_CHAR_RACE_SKILLS[race] != -1) {
+		raceSkillStr = Res.SKILL_NAMES[Res.NEW_CHAR_RACE_SKILLS[race]];
+	}
+
+	// Set up color to use for each skill string to be displayed, based
+	// on whether each class is allowed or not for the given attributes
+	int classColors[TOTAL_CLASSES];
+	Common::fill(&classColors[0], &classColors[TOTAL_CLASSES], 0);
+	for (int classNum = CLASS_KNIGHT; classNum <= CLASS_RANGER; ++classNum) {
+		if (allowedClasses[classNum]) {
+			if (classId == -1 && (foundClass == -1 || foundClass < classNum))
+				foundClass = classNum;
+			classColors[classNum] = 4;
+		}
+	}
+
+	// Return stats details and character class
+	msg = Common::String::format(Res.NEW_CHAR_STATS, Res.RACE_NAMES[race], Res.SEX_NAMES[sex],
+		attribs[MIGHT], attribs[INTELLECT], attribs[PERSONALITY],
+		attribs[ENDURANCE], attribs[SPEED], attribs[ACCURACY], attribs[LUCK],
+		classColors[CLASS_KNIGHT], classColors[CLASS_PALADIN],
+		classColors[CLASS_ARCHER], classColors[CLASS_CLERIC],
+		classColors[CLASS_SORCERER], classColors[CLASS_ROBBER],
+		classColors[CLASS_NINJA], classColors[CLASS_BARBARIAN],
+		classColors[CLASS_DRUID], classColors[CLASS_RANGER],
+		skillStr.c_str(), raceSkillStr.c_str(), classStr.c_str()
+	);
+	return classId == -1 ? foundClass : selectedClass;
+}
+
+void CreateCharacterDialog::printSelectionArrow(SpriteResource &icons, int selectedClass) {
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[0];
+	icons.draw(w, 61, Common::Point(220, 19));
+	icons.draw(w, 63, Common::Point(220, selectedClass * 11 + 21));
+	w.update();
+}
+
+void CreateCharacterDialog::drawDice(SpriteResource &dice) {
+	EventsManager &events = *_vm->_events;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[32];
+	Common::Point diceSize = dice.getFrameSize(0);
+
+	events.updateGameCounter();
+	dice.draw(w, 7, Common::Point(12, 11));
+
+	for (int diceNum = 0; diceNum < 3; ++diceNum) {
+		_diceFrame[diceNum] = (_diceFrame[diceNum] + 1) % 7;
+		_dicePos[diceNum] += _diceInc[diceNum];
+
+		if (_dicePos[diceNum].x < 13) {
+			_dicePos[diceNum].x = 13;
+			_diceInc[diceNum].x *= -1;
+		} else if (_dicePos[diceNum].x >= (163 - diceSize.x)) {
+			_dicePos[diceNum].x = 163 - diceSize.x;
+			_diceInc[diceNum].x *= -1;
+		}
+
+		if (_dicePos[diceNum].y < 12) {
+			_dicePos[diceNum].y = 12;
+			_diceInc[diceNum].y *= -1;
+		} else if (_dicePos[diceNum].y >= (93 - diceSize.y)) {
+			_dicePos[diceNum].y = 93 - diceSize.y;
+			_diceInc[diceNum].y *= -1;
+		}
+
+		dice.draw(w, _diceFrame[diceNum], _dicePos[diceNum]);
+	}
+
+	w.update();
+
+	// Wait for keypress
+	events.wait(1);
+	checkEvents(_vm);
+}
+
+int CreateCharacterDialog::exchangeAttribute(int srcAttr) {
+	EventsManager &events = *_vm->_events;
+	Windows &windows = *_vm->_windows;
+	SpriteResource icons;
+	icons.load("create2.icn");
+
+	saveButtons();
+	addButton(Common::Rect(118, 58, 142, 78), Common::KEYCODE_ESCAPE, &icons);
+	addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_m);
+	addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i);
+	addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p);
+	addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e);
+	addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s);
+	addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a);
+	addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l);
+
+	Window &w = windows[26];
+	w.open();
+	w.writeString(Common::String::format(Res.EXCHANGE_ATTR_WITH, Res.STAT_NAMES[srcAttr - 1]));
+	icons.draw(w, 0, Common::Point(118, 58));
+	w.update();
+
+	int result = 0;
+	bool breakFlag = false;
+	while (!_vm->shouldExit() && !breakFlag) {
+		// Wait for an action
+		do {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		} while (!_vm->shouldExit() && !_buttonValue);
+
+		Attribute destAttr;
+		switch (_buttonValue) {
+		case Common::KEYCODE_m:
+			destAttr = MIGHT;
+			break;
+		case Common::KEYCODE_i:
+			destAttr = INTELLECT;
+			break;
+		case Common::KEYCODE_p:
+			destAttr = PERSONALITY;
+			break;
+		case Common::KEYCODE_e:
+			destAttr = ENDURANCE;
+			break;
+		case Common::KEYCODE_s:
+			destAttr = SPEED;
+			break;
+		case Common::KEYCODE_a:
+			destAttr = ACCURACY;
+			break;
+		case Common::KEYCODE_l:
+			destAttr = LUCK;
+			break;
+		case Common::KEYCODE_ESCAPE:
+			result = 0;
+			breakFlag = true;
+			continue;
+		default:
+			continue;
+		}
+
+		if ((srcAttr - 1) != destAttr) {
+			result = destAttr + 1;
+			break;
+		}
+	}
+
+	w.close();
+	_buttonValue = 0;
+	restoreButtons();
+
+	return result;
+}
+
+bool CreateCharacterDialog::saveCharacter(Character &c, int classId,
+		Race race, Sex sex, uint attribs[TOTAL_ATTRIBUTES]) {
+	if (classId == -1) {
+		ErrorScroll::show(_vm, Res.SELECT_CLASS_BEFORE_SAVING);
+		return false;
+	}
+
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+	Common::String name;
+	int result;
+	bool isDarkCc = _vm->_files->_isDarkCc;
+
+	saveButtons();
+	w.writeString(Res.NAME_FOR_NEW_CHARACTER);
+
+	result = Input::show(_vm, &w, name, 10, 200);
+	w.close();
+	restoreButtons();
+	if (!result)
+		return false;
+
+	// Save new character details
+	c.clear();
+	c._name = name;
+	c._savedMazeId = party._priorMazeId;
+	c._xeenSide = map._loadDarkSide;
+	c._sex = sex;
+	c._race = race;
+	c._class = (CharacterClass)classId;
+	c._level._permanent = isDarkCc ? 5 : 1;
+
+	c._might._permanent = attribs[MIGHT];
+	c._intellect._permanent = attribs[INTELLECT];
+	c._personality._permanent = attribs[PERSONALITY];
+	c._endurance._permanent = attribs[ENDURANCE];
+	c._speed._permanent = attribs[SPEED];
+	c._accuracy._permanent = attribs[ACCURACY];
+	c._luck._permanent = attribs[LUCK];
+
+	c._magicResistence._permanent = Res.RACE_MAGIC_RESISTENCES[race];
+	c._fireResistence._permanent = Res.RACE_FIRE_RESISTENCES[race];
+	c._electricityResistence._permanent = Res.RACE_ELECTRIC_RESISTENCES[race];
+	c._coldResistence._permanent = Res.RACE_COLD_RESISTENCES[race];
+	c._energyResistence._permanent = Res.RACE_ENERGY_RESISTENCES[race];
+	c._poisonResistence._permanent = Res.RACE_POISON_RESISTENCES[race];
+
+	c._birthYear = party._year - 18;
+	c._birthDay = party._day;
+	c._hasSpells = false;
+	c._currentSpell = -1;
+
+	// Set up any default spells for the character's class
+	for (int idx = 0; idx < 4; ++idx) {
+		if (Res.NEW_CHARACTER_SPELLS[c._class][idx] != -1) {
+			c._hasSpells = true;
+			c._currentSpell = Res.NEW_CHARACTER_SPELLS[c._class][idx];
+			c._spells[c._currentSpell] = true;
+		}
+	}
+
+	int classSkill = Res.NEW_CHAR_SKILLS[c._class];
+	if (classSkill != -1)
+		c._skills[classSkill] = 1;
+
+	int raceSkill = Res.NEW_CHAR_RACE_SKILLS[c._race];
+	if (raceSkill != -1)
+		c._skills[raceSkill] = 1;
+
+	c._currentHp = c.getMaxHP();
+	c._currentSp = c.getMaxSP();
+	return true;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs_create_char.h b/engines/xeen/dialogs_create_char.h
new file mode 100644
index 0000000..6a33bcf
--- /dev/null
+++ b/engines/xeen/dialogs_create_char.h
@@ -0,0 +1,102 @@
+/* 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_CREATE_CHAR_H
+#define XEEN_DIALOGS_CREATE_CHAR_H
+
+#include "xeen/dialogs.h"
+#include "xeen/character.h"
+
+namespace Xeen {
+
+class CreateCharacterDialog : public ButtonContainer  {
+private:
+	SpriteResource _icons;
+	SpriteResource _dice;
+	int _diceFrame[3];
+	Common::Point _dicePos[3];
+	Common::Point _diceInc[3];
+private:
+	/**
+	 * Constructor
+	 */
+	CreateCharacterDialog(XeenEngine *vm);
+
+	/**
+	 * Loads the buttons for the dialog
+	 */
+	void loadButtons();
+
+	/**
+	 * Print the dice animation
+	 */
+	void drawDice(SpriteResource &dice);
+
+	/**
+	 * Executes the dialog
+	 */
+	void execute();
+
+	/**
+	 * Exchanging two attributes for the character being rolled
+	 */
+	int exchangeAttribute(int srcAttr);
+
+	/**
+	 * Set a list of flags for which classes the passed attribute set meet the
+	 * minimum requirements of
+	 */
+	void checkClass(const uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]);
+
+	/**
+	 * Return details of the generated character
+	 */
+	int newCharDetails(const uint attribs[TOTAL_ATTRIBUTES],
+		bool allowedClasses[TOTAL_CLASSES], Race race, Sex sex, int classId,
+		int selectedClass, Common::String &msg);
+
+	/**
+	 * Print the selection arrow to indicate the selected class
+	 */
+	void printSelectionArrow(SpriteResource &icons, int selectedClass);
+
+	/**
+	 * Saves the rolled character into the roster
+	 */
+	bool saveCharacter(Character &c, int classId, Race race,
+		Sex sex, uint attribs[TOTAL_ATTRIBUTES]);
+
+	/**
+	 * Roll up some random values for the attributes, and return both them as
+	 * well as a list of classes that the attributes meet the requirements for
+	 */
+	void throwDice(uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]);
+public:
+	/**
+	 * Shows the Create Character dialog
+	 */
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_CREATE_CHAR_H */
diff --git a/engines/xeen/dialogs_party.cpp b/engines/xeen/dialogs_party.cpp
index 12d8074..c0c58cc 100644
--- a/engines/xeen/dialogs_party.cpp
+++ b/engines/xeen/dialogs_party.cpp
@@ -20,8 +20,8 @@
  *
  */
 
-#include "common/scummsys.h"
 #include "xeen/dialogs_char_info.h"
+#include "xeen/dialogs_create_char.h"
 #include "xeen/dialogs_party.h"
 #include "xeen/dialogs_input.h"
 #include "xeen/dialogs_query.h"
@@ -205,7 +205,8 @@ void PartyDialog::execute() {
 					screen.fadeOut();
 					w.close();
 
-					createChar();
+					// Show the create character dialog
+					CreateCharacterDialog::show(_vm);
 
 					party.copyPartyToRoster();
 					//_vm->_saves->writeCharFile();
@@ -372,330 +373,6 @@ void PartyDialog::startingCharChanged(int firstDisplayChar) {
 	w.update();
 }
 
-void PartyDialog::createChar() {
-	EventsManager &events = *_vm->_events;
-	Party &party = *_vm->_party;
-	Screen &screen = *_vm->_screen;
-	Windows &windows = *_vm->_windows;
-	Window &w = windows[0];
-	SpriteResource dice, icons;
-	Common::Array<int> freeCharList;
-	int classId;
-	int selectedClass = 0;
-	bool hasFadedIn = false;
-	bool restartFlag = true;
-	uint attribs[TOTAL_ATTRIBUTES];
-	bool allowedClasses[TOTAL_CLASSES];
-	Race race = HUMAN;
-	Sex sex = MALE;
-	Common::String msg, details;
-	int charIndex = 0;
-
-	Mode oldMode = _vm->_mode;
-	_vm->_mode = MODE_4;
-	dice.load("dice.vga");
-	icons.load("create.icn");
-
-	_dicePos[0] = Common::Point(20, 17);
-	_dicePos[1] = Common::Point(112, 35);
-	_dicePos[2] = Common::Point(61, 50);
-	_diceFrame[0] = 0;
-	_diceFrame[1] = 2;
-	_diceFrame[2] = 4;
-	_diceInc[0] = Common::Point(10, -10);
-	_diceInc[1] = Common::Point(-10, -10);
-	_diceInc[2] = Common::Point(-10, 10);
-
-	// Add buttons
-	saveButtons();
-	addButton(Common::Rect(132, 98, 156, 118), Common::KEYCODE_r, &icons);
-	addButton(Common::Rect(132, 128, 156, 148), Common::KEYCODE_c, &icons);
-	addButton(Common::Rect(132, 158, 156, 178), Common::KEYCODE_ESCAPE, &icons);
-	addButton(Common::Rect(86, 98, 110, 118), Common::KEYCODE_UP, &icons);
-	addButton(Common::Rect(86, 120, 110, 140), Common::KEYCODE_DOWN, &icons);
-	addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_n, nullptr);
-	addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i, nullptr);
-	addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p, nullptr);
-	addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e, nullptr);
-	addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s, nullptr);
-	addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a, nullptr);
-	addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l, nullptr);
-	addButton(Common::Rect(227, 19, 239, 29), 1000, nullptr);
-	addButton(Common::Rect(227, 30, 239, 40), 1001, nullptr);
-	addButton(Common::Rect(227, 41, 239, 51), 1002, nullptr);
-	addButton(Common::Rect(227, 52, 239, 62), 1003, nullptr);
-	addButton(Common::Rect(227, 63, 239, 73), 1004, nullptr);
-	addButton(Common::Rect(227, 74, 239, 84), 1005, nullptr);
-	addButton(Common::Rect(227, 85, 239, 95), 1006, nullptr);
-	addButton(Common::Rect(227, 96, 239, 106), 1007, nullptr);
-	addButton(Common::Rect(227, 107, 239, 117), 1008, nullptr);
-	addButton(Common::Rect(227, 118, 239, 128), 1009, nullptr);
-
-	// Load the background
-	screen.loadBackground("create.raw");
-	events.setCursor(0);
-
-	while (!_vm->shouldExit()) {
-		classId = -1;
-
-		if (restartFlag) {
-			// Build up list of roster slot indexes that are free
-			freeCharList.clear();
-			for (uint idx = 0; idx < XEEN_TOTAL_CHARACTERS; ++idx) {
-				if (party._roster[idx]._name.empty())
-					freeCharList.push_back(idx);
-			}
-			charIndex = 0;
-			//bool flag9 = true;
-
-			if (freeCharList.size() == XEEN_TOTAL_CHARACTERS)
-				break;
-
-			// Get and race and sex for the given character
-			race = (Race)((freeCharList[charIndex] / 4) % 5);
-			sex = (Sex)(freeCharList[charIndex] & 1);
-
-			// Randomly determine attributes, and which classes they allow
-			throwDice(attribs, allowedClasses);
-
-			// Get the display of the rolled character details
-			selectedClass = newCharDetails(attribs, allowedClasses,
-				race, sex, classId, selectedClass, details);
-			msg = Common::String::format(Res.CREATE_CHAR_DETAILS,
-				details.c_str());
-
-			// Draw the screen
-			icons.draw(w, 10, Common::Point(168, 19));
-			icons.draw(w, 12, Common::Point(168, 43));
-			icons.draw(w, 14, Common::Point(168, 67));
-			icons.draw(w, 16, Common::Point(168, 91));
-			icons.draw(w, 18, Common::Point(168, 115));
-			icons.draw(w, 20, Common::Point(168, 139));
-			icons.draw(w, 22, Common::Point(168, 163));
-			for (int idx = 0; idx < 9; ++idx)
-				icons.draw(w, 24 + idx * 2, Common::Point(227, 19 + 11 * idx));
-
-			for (int idx = 0; idx < 7; ++idx)
-				icons.draw(w, 50 + idx, Common::Point(195, 31 + 24 * idx));
-
-			icons.draw(w, 57, Common::Point(62, 148));
-			icons.draw(w, 58, Common::Point(62, 158));
-			icons.draw(w, 59, Common::Point(62, 168));
-			icons.draw(w, 61, Common::Point(220, 19));
-			icons.draw(w, 64, Common::Point(220, 155));
-			icons.draw(w, 65, Common::Point(220, 170));
-
-			party._roster[freeCharList[charIndex]]._faceSprites->draw(
-				w, 0, Common::Point(27, 102));
-
-			icons.draw(w, 0, Common::Point(132, 98));
-			icons.draw(w, 2, Common::Point(132, 128));
-			icons.draw(w, 4, Common::Point(132, 158));
-			icons.draw(w, 6, Common::Point(86, 98));
-			icons.draw(w, 8, Common::Point(86, 120));
-
-			w.writeString(msg);
-			w.update();
-
-			// Draw the arrow for the selected class, if applicable
-			if (selectedClass != -1)
-				printSelectionArrow(icons, selectedClass);
-
-			// Draw the dice
-			drawDice(dice);
-			if (!hasFadedIn) {
-				screen.fadeIn();
-				hasFadedIn = true;
-			}
-
-			restartFlag = false;
-		}
-
-		// Animate the dice until a user action occurs
-		_buttonValue = 0;
-		while (!_vm->shouldExit() && !_buttonValue)
-			drawDice(dice);
-
-		// Handling for different actions
-		switch (_buttonValue) {
-		case Common::KEYCODE_UP:
-			if (charIndex == 0)
-				continue;
-
-			race = (Race)((freeCharList[charIndex] / 4) % 5);
-			sex = (Sex)(freeCharList[charIndex] & 1);
-			break;
-
-		case Common::KEYCODE_DOWN:
-			if (++charIndex == (int)freeCharList.size()) {
-				--charIndex;
-				continue;
-			} else {
-				race = (Race)((freeCharList[charIndex] / 4) % 5);
-				sex = (Sex)(freeCharList[charIndex] & 1);
-			}
-			break;
-
-		case Common::KEYCODE_PAGEUP:
-			for (int tempClass = selectedClass - 1; tempClass >= 0; --tempClass) {
-				if (allowedClasses[tempClass]) {
-					selectedClass = tempClass;
-					break;
-				}
-			}
-
-			printSelectionArrow(icons, selectedClass);
-			continue;
-
-		case Common::KEYCODE_PAGEDOWN:
-			break;
-
-		case Common::KEYCODE_m:
-		case Common::KEYCODE_i:
-		case Common::KEYCODE_p:
-		case Common::KEYCODE_e:
-		case Common::KEYCODE_s:
-		case Common::KEYCODE_a:
-		case Common::KEYCODE_l: {
-			Attribute srcAttrib, destAttrib;
-			if (_buttonValue == Common::KEYCODE_m)
-				srcAttrib = MIGHT;
-			else if (_buttonValue == Common::KEYCODE_i)
-				srcAttrib = INTELLECT;
-			else if (_buttonValue == Common::KEYCODE_p)
-				srcAttrib = PERSONALITY;
-			else if (_buttonValue == Common::KEYCODE_e)
-				srcAttrib = ENDURANCE;
-			else if (_buttonValue == Common::KEYCODE_s)
-				srcAttrib = SPEED;
-			else if (_buttonValue == Common::KEYCODE_a)
-				srcAttrib = ACCURACY;
-			else
-				srcAttrib = LUCK;
-
-			_vm->_mode = MODE_86;
-			icons.draw(w, srcAttrib * 2 + 11, Common::Point(
-				_buttons[srcAttrib + 5]._bounds.left, _buttons[srcAttrib + 5]._bounds.top));
-			w.update();
-
-			int destAttribVal = exchangeAttribute(srcAttrib + 1);
-			if (destAttribVal) {
-				destAttrib = (Attribute)(destAttribVal - 1);
-				icons.draw(w, destAttrib * 2 + 11, Common::Point(
-					_buttons[destAttrib + 10]._bounds.left,
-					_buttons[destAttrib + 10]._bounds.top));
-				w.update();
-
-				SWAP(attribs[srcAttrib], attribs[destAttrib]);
-				checkClass(attribs, allowedClasses);
-				classId = -1;
-				selectedClass = newCharDetails(attribs, allowedClasses,
-					race, sex, classId, selectedClass, msg);
-			} else {
-				icons.draw(w, srcAttrib * 2 + 10, Common::Point(
-					_buttons[srcAttrib + 5]._bounds.left,
-					_buttons[srcAttrib + 5]._bounds.top));
-				w.update();
-				_vm->_mode = MODE_SLEEPING;
-				continue;
-			}
-			break;
-		}
-
-		case 1000:
-		case 1001:
-		case 1002:
-		case 1003:
-		case 1004:
-		case 1005:
-		case 1006:
-		case 1007:
-		case 1008:
-		case 1009:
-			if (allowedClasses[_buttonValue - 1000]) {
-				selectedClass = classId = _buttonValue - 1000;
-			}
-			break;
-
-		case Common::KEYCODE_c: {
-			_vm->_mode = MODE_FF;
-			bool result = saveCharacter(party._roster[freeCharList[charIndex]],
-				classId, race, sex, attribs);
-			_vm->_mode = MODE_4;
-
-			if (result)
-				restartFlag = true;
-			continue;
-		}
-
-		case Common::KEYCODE_RETURN:
-			classId = selectedClass;
-			break;
-
-		case Common::KEYCODE_SPACE:
-		case Common::KEYCODE_r:
-			// Re-roll the attributes
-			throwDice(attribs, allowedClasses);
-			classId = -1;
-			break;
-
-		default:
-			// For all other keypresses, skip the code below the switch
-			// statement, and go to wait for the next key
-			continue;
-		}
-
-		if (_buttonValue != Common::KEYCODE_PAGEDOWN) {
-			selectedClass = newCharDetails(attribs, allowedClasses,
-				race, sex, classId, selectedClass, msg);
-
-			for (int idx = 0; idx < 7; ++idx)
-				icons.draw(w, 10 + idx * 2, Common::Point(168, 19 + idx * 24));
-			for (int idx = 0; idx < 10; ++idx)
-				icons.draw(w, 24 + idx * 2, Common::Point(227, 19 + idx * 11));
-			for (int idx = 0; idx < 8; ++idx)
-				icons.draw(w, 50 + idx, Common::Point(195, 31 + idx * 24));
-
-			icons.draw(w, 57, Common::Point(62, 148));
-			icons.draw(w, 58, Common::Point(62, 158));
-			icons.draw(w, 59, Common::Point(62, 168));
-			icons.draw(w, 61, Common::Point(220, 19));
-			icons.draw(w, 64, Common::Point(220, 155));
-			icons.draw(w, 65, Common::Point(220, 170));
-
-			party._roster[freeCharList[charIndex]]._faceSprites->draw(w, 0,
-				Common::Point(27, 102));
-
-			icons.draw(w, 0, Common::Point(132, 98));
-			icons.draw(w, 2, Common::Point(132, 128));
-			icons.draw(w, 4, Common::Point(132, 158));
-			icons.draw(w, 6, Common::Point(86, 98));
-			icons.draw(w, 8, Common::Point(86, 120));
-
-			w.writeString(msg);
-			w.update();
-
-			if (selectedClass != -1) {
-				printSelectionArrow(icons, selectedClass);
-				continue;
-			}
-		}
-
-		// Move to next available class, or if the code block above resulted in
-		// selectedClass being -1, move to select the first available class
-		for (int tempClass = selectedClass + 1; tempClass <= CLASS_RANGER; ++tempClass) {
-			if (allowedClasses[tempClass]) {
-				selectedClass = tempClass;
-				break;
-			}
-		}
-
-		printSelectionArrow(icons, selectedClass);
-	} while (!_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
-
-	_vm->_mode = oldMode;
-}
-
 int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) {
 	EventsManager &events = *_vm->_events;
 	Party &party = *_vm->_party;
@@ -768,289 +445,4 @@ int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) {
 	return result == -1 ? 0 : result;
 }
 
-void PartyDialog::throwDice(uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]) {
-	bool repeat = true;
-	do {
-		// Default all the attributes to zero
-		Common::fill(&attribs[0], &attribs[TOTAL_ATTRIBUTES], 0);
-
-		// Assign random amounts to each attribute
-		for (int idx1 = 0; idx1 < 3; ++idx1) {
-			for (int idx2 = 0; idx2 < TOTAL_ATTRIBUTES; ++idx2) {
-				attribs[idx1] += _vm->getRandomNumber(10, 79) / 10;
-			}
-		}
-
-		// Check which classes are allowed based on the rolled attributes
-		checkClass(attribs, allowedClasses);
-
-		// Only exit if the attributes allow for at least one class
-		for (int idx = 0; idx < TOTAL_CLASSES; ++idx) {
-			if (allowedClasses[idx])
-				repeat = false;
-		}
-	} while (repeat);
-}
-
-void PartyDialog::checkClass(const uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]) {
-	allowedClasses[CLASS_KNIGHT] = attribs[MIGHT] >= 15;
-	allowedClasses[CLASS_PALADIN] = attribs[MIGHT] >= 13
-		&& attribs[PERSONALITY] >= 13 && attribs[ENDURANCE] >= 13;
-	allowedClasses[CLASS_ARCHER] = attribs[INTELLECT] >= 13 && attribs[ACCURACY] >= 13;
-	allowedClasses[CLASS_CLERIC] = attribs[PERSONALITY] >= 13;
-	allowedClasses[CLASS_SORCERER] = attribs[INTELLECT] >= 13;
-	allowedClasses[CLASS_ROBBER] = attribs[LUCK] >= 13;
-	allowedClasses[CLASS_NINJA] = attribs[SPEED] >= 13 && attribs[ACCURACY] >= 13;
-	allowedClasses[CLASS_BARBARIAN] = attribs[ENDURANCE] >= 15;
-	allowedClasses[CLASS_DRUID] = attribs[INTELLECT] >= 15 && attribs[PERSONALITY] >= 15;
-	allowedClasses[CLASS_RANGER] = attribs[INTELLECT] >= 12 && attribs[PERSONALITY] >= 12
-		&& attribs[ENDURANCE] >= 12 && attribs[SPEED] >= 12;
-}
-
-int PartyDialog::newCharDetails(const uint attribs[TOTAL_ATTRIBUTES],
-		bool allowedClasses[TOTAL_CLASSES], Race race, Sex sex, int classId,
-		int selectedClass, Common::String &msg) {
-	int foundClass = -1;
-	Common::String skillStr, classStr, raceSkillStr;
-
-	// If a selected class is provided, set the default skill for that class
-	if (classId != -1 && Res.NEW_CHAR_SKILLS[classId] != -1) {
-		const char *skillP = Res.SKILL_NAMES[Res.NEW_CHAR_SKILLS[classId]];
-		skillStr = Common::String(skillP, skillP + Res.NEW_CHAR_SKILLS_LEN[classId]);
-	}
-
-	// If a class is provided, set the class name
-	if (classId != -1) {
-		classStr = Common::String::format("\t062\v168%s", Res.CLASS_NAMES[classId]);
-	}
-
-	// Set up default skill for the race, if any
-	if (Res.NEW_CHAR_RACE_SKILLS[race] != -1) {
-		raceSkillStr = Res.SKILL_NAMES[Res.NEW_CHAR_RACE_SKILLS[race]];
-	}
-
-	// Set up color to use for each skill string to be displayed, based
-	// on whether each class is allowed or not for the given attributes
-	int classColors[TOTAL_CLASSES];
-	Common::fill(&classColors[0], &classColors[TOTAL_CLASSES], 0);
-	for (int classNum = CLASS_KNIGHT; classNum <= CLASS_RANGER; ++classNum) {
-		if (allowedClasses[classNum]) {
-			if (classId == -1 && (foundClass == -1 || foundClass < classNum))
-				foundClass = classNum;
-			classColors[classNum] = 4;
-		}
-	}
-
-	// Return stats details and character class
-	msg = Common::String::format(Res.NEW_CHAR_STATS, Res.RACE_NAMES[race], Res.SEX_NAMES[sex],
-		attribs[MIGHT], attribs[INTELLECT], attribs[PERSONALITY],
-		attribs[ENDURANCE], attribs[SPEED], attribs[ACCURACY], attribs[LUCK],
-		classColors[CLASS_KNIGHT], classColors[CLASS_PALADIN],
-		classColors[CLASS_ARCHER], classColors[CLASS_CLERIC],
-		classColors[CLASS_SORCERER], classColors[CLASS_ROBBER],
-		classColors[CLASS_NINJA], classColors[CLASS_BARBARIAN],
-		classColors[CLASS_DRUID], classColors[CLASS_RANGER],
-		skillStr.c_str(), raceSkillStr.c_str(), classStr.c_str()
-	);
-	return classId == -1 ? foundClass : selectedClass;
-}
-
-void PartyDialog::printSelectionArrow(SpriteResource &icons, int selectedClass) {
-	Windows &windows = *_vm->_windows;
-	Window &w = windows[0];
-	icons.draw(w, 61, Common::Point(220, 19));
-	icons.draw(w, 63, Common::Point(220, selectedClass * 11 + 21));
-	w.update();
-}
-
-void PartyDialog::drawDice(SpriteResource &dice) {
-	EventsManager &events = *_vm->_events;
-	Windows &windows = *_vm->_windows;
-	Window &w = windows[32];
-	Common::Point diceSize = dice.getFrameSize(0);
-
-	events.updateGameCounter();
-	dice.draw(w, 7, Common::Point(12, 11));
-
-	for (int diceNum = 0; diceNum < 3; ++diceNum) {
-		_diceFrame[diceNum] = (_diceFrame[diceNum] + 1) % 7;
-		_dicePos[diceNum] += _diceInc[diceNum];
-
-		if (_dicePos[diceNum].x < 13) {
-			_dicePos[diceNum].x = 13;
-			_diceInc[diceNum].x *= -1;
-		} else if (_dicePos[diceNum].x >= (163 - diceSize.x)) {
-			_dicePos[diceNum].x = 163 - diceSize.x;
-			_diceInc[diceNum].x *= -1;
-		}
-
-		if (_dicePos[diceNum].y < 12) {
-			_dicePos[diceNum].y = 12;
-			_diceInc[diceNum].y *= -1;
-		} else if (_dicePos[diceNum].y >= (93 - diceSize.y)) {
-			_dicePos[diceNum].y = 93 - diceSize.y;
-			_diceInc[diceNum].y *= -1;
-		}
-
-		dice.draw(w, _diceFrame[diceNum], _dicePos[diceNum]);
-	}
-
-	w.update();
-
-	// Wait for keypress
-	events.wait(1);
-	checkEvents(_vm);
-}
-
-int PartyDialog::exchangeAttribute(int srcAttr) {
-	EventsManager &events = *_vm->_events;
-	Windows &windows = *_vm->_windows;
-	SpriteResource icons;
-	icons.load("create2.icn");
-
-	saveButtons();
-	addButton(Common::Rect(118, 58, 142, 78), Common::KEYCODE_ESCAPE, &icons);
-	addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_m);
-	addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i);
-	addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p);
-	addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e);
-	addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s);
-	addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a);
-	addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l);
-
-	Window &w = windows[26];
-	w.open();
-	w.writeString(Common::String::format(Res.EXCHANGE_ATTR_WITH, Res.STAT_NAMES[srcAttr - 1]));
-	icons.draw(w, 0, Common::Point(118, 58));
-	w.update();
-
-	int result = 0;
-	bool breakFlag = false;
-	while (!_vm->shouldExit() && !breakFlag) {
-		// Wait for an action
-		do {
-			events.pollEventsAndWait();
-			checkEvents(_vm);
-		} while (!_vm->shouldExit() && !_buttonValue);
-
-		Attribute destAttr;
-		switch (_buttonValue) {
-		case Common::KEYCODE_m:
-			destAttr = MIGHT;
-			break;
-		case Common::KEYCODE_i:
-			destAttr = INTELLECT;
-			break;
-		case Common::KEYCODE_p:
-			destAttr = PERSONALITY;
-			break;
-		case Common::KEYCODE_e:
-			destAttr = ENDURANCE;
-			break;
-		case Common::KEYCODE_s:
-			destAttr = SPEED;
-			break;
-		case Common::KEYCODE_a:
-			destAttr = ACCURACY;
-			break;
-		case Common::KEYCODE_l:
-			destAttr = LUCK;
-			break;
-		case Common::KEYCODE_ESCAPE:
-			result = 0;
-			breakFlag = true;
-			continue;
-		default:
-			continue;
-		}
-
-		if ((srcAttr - 1) != destAttr) {
-			result = destAttr + 1;
-			break;
-		}
-	}
-
-	w.close();
-	_buttonValue = 0;
-	restoreButtons();
-
-	return result;
-}
-
-bool PartyDialog::saveCharacter(Character &c, int classId,
-		Race race, Sex sex, uint attribs[TOTAL_ATTRIBUTES]) {
-	if (classId == -1) {
-		ErrorScroll::show(_vm, Res.SELECT_CLASS_BEFORE_SAVING);
-		return false;
-	}
-
-	Map &map = *_vm->_map;
-	Party &party = *_vm->_party;
-	Windows &windows = *_vm->_windows;
-	Window &w = windows[6];
-	Common::String name;
-	int result;
-	bool isDarkCc = _vm->_files->_isDarkCc;
-
-	saveButtons();
-	w.writeString(Res.NAME_FOR_NEW_CHARACTER);
-
-	result = Input::show(_vm, &w, name, 10, 200);
-	w.close();
-	restoreButtons();
-	if (!result)
-		return false;
-
-	// Save new character details
-	c.clear();
-	c._name = name;
-	c._savedMazeId = party._priorMazeId;
-	c._xeenSide = map._loadDarkSide;
-	c._sex = sex;
-	c._race = race;
-	c._class = (CharacterClass)classId;
-	c._level._permanent = isDarkCc ? 5 : 1;
-
-	c._might._permanent = attribs[MIGHT];
-	c._intellect._permanent = attribs[INTELLECT];
-	c._personality._permanent = attribs[PERSONALITY];
-	c._endurance._permanent = attribs[ENDURANCE];
-	c._speed._permanent = attribs[SPEED];
-	c._accuracy._permanent = attribs[ACCURACY];
-	c._luck._permanent = attribs[LUCK];
-
-	c._magicResistence._permanent = Res.RACE_MAGIC_RESISTENCES[race];
-	c._fireResistence._permanent = Res.RACE_FIRE_RESISTENCES[race];
-	c._electricityResistence._permanent = Res.RACE_ELECTRIC_RESISTENCES[race];
-	c._coldResistence._permanent = Res.RACE_COLD_RESISTENCES[race];
-	c._energyResistence._permanent = Res.RACE_ENERGY_RESISTENCES[race];
-	c._poisonResistence._permanent = Res.RACE_POISON_RESISTENCES[race];
-
-	c._birthYear = party._year - 18;
-	c._birthDay = party._day;
-	c._hasSpells = false;
-	c._currentSpell = -1;
-
-	// Set up any default spells for the character's class
-	for (int idx = 0; idx < 4; ++idx) {
-		if (Res.NEW_CHARACTER_SPELLS[c._class][idx] != -1) {
-			c._hasSpells = true;
-			c._currentSpell = Res.NEW_CHARACTER_SPELLS[c._class][idx];
-			c._spells[c._currentSpell] = true;
-		}
-	}
-
-	int classSkill = Res.NEW_CHAR_SKILLS[c._class];
-	if (classSkill != -1)
-		c._skills[classSkill] = 1;
-
-	int raceSkill = Res.NEW_CHAR_RACE_SKILLS[c._race];
-	if (raceSkill != -1)
-		c._skills[raceSkill] = 1;
-
-	c._currentHp = c.getMaxHP();
-	c._currentSp = c.getMaxSP();
-	return true;
-}
-
 } // End of namespace Xeen
diff --git a/engines/xeen/dialogs_party.h b/engines/xeen/dialogs_party.h
index 84b9857..ba9c34c 100644
--- a/engines/xeen/dialogs_party.h
+++ b/engines/xeen/dialogs_party.h
@@ -31,6 +31,9 @@
 
 namespace Xeen {
 
+/**
+ * Shows the Party dialog that's shown when signing into an inn
+ */
 class PartyDialog : public ButtonContainer, public PartyDrawer {
 private:
 	XeenEngine *_vm;
@@ -38,71 +41,44 @@ private:
 	DrawStruct _faceDrawStructs[4];
 	Common::String _partyDetails;
 	Common::Array<int> _charList;
-	int _diceFrame[3];
-	Common::Point _dicePos[3];
-	Common::Point _diceInc[3];
-
-	PartyDialog(XeenEngine *vm);
-
-	void execute();
-
-	void loadButtons();
-
-	void initDrawStructs();
-
-	void setupBackground();
 
 	/**
-	 * Sets up the faces from the avaialble roster for display in the party dialog
+	 * Constructor
 	 */
-	void setupFaces(int firstDisplayChar, bool updateFlag);
-
-	void startingCharChanged(int firstDisplayChar);
-
-	void createChar();
-
-	int selectCharacter(bool isDelete, int firstDisplayChar);
+	PartyDialog(XeenEngine *vm);
 
 	/**
-	 * Roll up some random values for the attributes, and return both them as
-	 * well as a list of classes that the attributes meet the requirements for
+	 * Executes the dialog
 	 */
-	void throwDice(uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]);
+	void execute();
 
 	/**
-	 * Set a list of flags for which classes the passed attribute set meet the
-	 * minimum requirements of
+	 * Loads buttons for the dialog
 	 */
-	void checkClass(const uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]);
+	void loadButtons();
 
 	/**
-	 * Return details of the generated character
+	 * Initialises a list of elements to draw
 	 */
-	int newCharDetails(const uint attribs[TOTAL_ATTRIBUTES],
-		bool allowedClasses[TOTAL_CLASSES], Race race, Sex sex, int classId,
-		int selectedClass, Common::String &msg);
+	void initDrawStructs();
 
 	/**
-	 * Print the selection arrow to indicate the selected class
+	 * Sets up the background
 	 */
-	void printSelectionArrow(SpriteResource &icons, int selectedClass);
+	void setupBackground();
 
 	/**
-	 * Print the dice animation
+	 * Sets up the faces from the avaialble roster for display in the party dialog
 	 */
-	void drawDice(SpriteResource &dice);
+	void setupFaces(int firstDisplayChar, bool updateFlag);
 
-	/**
-	 * Exchanging two attributes for the character being rolled
-	 */
-	int exchangeAttribute(int srcAttr);
+	void startingCharChanged(int firstDisplayChar);
 
+	int selectCharacter(bool isDelete, int firstDisplayChar);
+public:
 	/**
-	 * Saves the rolled character into the roster
+	 * Show the Party dialog
 	 */
-	bool saveCharacter(Character &c, int classId, Race race,
-		Sex sex, uint attribs[TOTAL_ATTRIBUTES]);
-public:
 	static void show(XeenEngine *vm);
 };
 
diff --git a/engines/xeen/module.mk b/engines/xeen/module.mk
index c6b8f45..c464dbc 100644
--- a/engines/xeen/module.mk
+++ b/engines/xeen/module.mk
@@ -17,6 +17,7 @@ MODULE_OBJS := \
 	dialogs_awards.o \
 	dialogs_char_info.o \
 	dialogs_control_panel.o \
+	dialogs_create_char.o \
 	dialogs_dismiss.o \
 	dialogs_exchange.o \
 	dialogs_fight_options.o \





More information about the Scummvm-git-logs mailing list