diff options
| -rw-r--r-- | engines/xeen/character.h | 4 | ||||
| -rw-r--r-- | engines/xeen/dialogs_party.cpp | 246 | ||||
| -rw-r--r-- | engines/xeen/dialogs_party.h | 12 | ||||
| -rw-r--r-- | engines/xeen/resources.cpp | 21 | ||||
| -rw-r--r-- | engines/xeen/resources.h | 7 | 
5 files changed, 287 insertions, 3 deletions
| diff --git a/engines/xeen/character.h b/engines/xeen/character.h index 492e5e298f..9e8687dbd7 100644 --- a/engines/xeen/character.h +++ b/engines/xeen/character.h @@ -49,13 +49,13 @@ enum Race { HUMAN = 0, ELF = 1, DWARF = 2, GNOME = 3, HALF_ORC = 4 };  enum CharacterClass {  	CLASS_KNIGHT = 0, CLASS_PALADIN = 1, CLASS_ARCHER = 2, CLASS_CLERIC = 3,  	CLASS_SORCERER = 4, CLASS_ROBBER = 5, CLASS_NINJA = 6, CLASS_BARBARIAN = 7, -	CLASS_DRUID = 8, CLASS_RANGER = 9, +	CLASS_DRUID = 8, CLASS_RANGER = 9, TOTAL_CLASSES = 10,  	CLASS_12 = 12, CLASS_15 = 15, CLASS_16 = 16  };  enum Attribute {  	MIGHT = 0, INTELLECT = 1, PERSONALITY = 2, ENDURANCE = 3, SPEED = 4, -	ACCURACY = 5, LUCK = 6 +	ACCURACY = 5, LUCK = 6, TOTAL_ATTRIBUTES = 7  };  enum Skill { diff --git a/engines/xeen/dialogs_party.cpp b/engines/xeen/dialogs_party.cpp index eece1e36fe..ff59363ead 100644 --- a/engines/xeen/dialogs_party.cpp +++ b/engines/xeen/dialogs_party.cpp @@ -372,7 +372,136 @@ void PartyDialog::startingCharChanged(int firstDisplayChar) {  }  void PartyDialog::createChar() { -	error("TODO: createChar"); +	EventsManager &events = *_vm->_events; +	Party &party = *_vm->_party; +	Screen &screen = *_vm->_screen; +	SpriteResource dice, icons; +	Mode oldMode = _vm->_mode; +	Common::Array<int> freeCharList; +	int selectedClass = 0; +	bool hasFadedIn = false; + +	dice.load("dice.vga"); +	icons.load("create.raw"); + +	// 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, 139, 29), 1000, nullptr); +	addButton(Common::Rect(227, 30, 139, 40), 1001, nullptr); +	addButton(Common::Rect(227, 41, 139, 51), 1002, nullptr); +	addButton(Common::Rect(227, 52, 139, 62), 1003, nullptr); +	addButton(Common::Rect(227, 63, 139, 73), 1004, nullptr); +	addButton(Common::Rect(227, 74, 139, 84), 1005, nullptr); +	addButton(Common::Rect(227, 85, 139, 95), 1006, nullptr); +	addButton(Common::Rect(227, 96, 139, 106), 1007, nullptr); +	addButton(Common::Rect(227, 107, 139, 117), 1008, nullptr); +	addButton(Common::Rect(227, 118, 139, 128), 1009, nullptr); + +	// Load the background +	screen.loadBackground("create.raw"); +	events.setCursor(0); + +	while (!_vm->shouldQuit()) { +		int classId = -1; + +		// 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); +		}		 +		int charIndex = 0; +		//bool flag9 = true; + +		if (freeCharList.size() == XEEN_TOTAL_CHARACTERS) +			break; + +		// Get and race and sex for the given character +		Race race = (Race)((freeCharList[charIndex] / 4) % 5); +		Sex sex = (Sex)(freeCharList[charIndex] & 1); + +		// Randomly determine attributes, and which classes they allow +		uint attribs[TOTAL_ATTRIBUTES]; +		bool allowedClasses[TOTAL_CLASSES]; +		throwDice(attribs, allowedClasses); + +		// Set up display of the rolled character details +		Common::String msg; +		selectedClass = newCharDetails(attribs, allowedClasses, +			race, sex, classId, selectedClass, msg); + +		// Draw the screen +		Window &w = screen._windows[0]; +		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(4); +			hasFadedIn = true; +		} + +		// Key handling loop +		while (!_vm->shouldQuit()) { +			// Animate the dice until a user action occurs +			_buttonValue = 0; +			while (!_vm->shouldQuit() && !_buttonValue) +				drawDice(dice); + +			// TODO +		} +		 +		// TODO: More +		error("TODO: createChar"); +	} + +	_vm->_mode = oldMode;  }  int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) { @@ -447,4 +576,119 @@ int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) {  	return result == -1 ? 0 : result;  } +/** + * 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 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); +} + +/** + * Set a list of flags for which classes the passed attribute set meet the + * minimum requirements of + */ +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; +} + +/** + * Return details of the generated character + */ +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 && NEW_CHAR_SKILLS[classId] != -1) { +		const char *skillP = SKILL_NAMES[NEW_CHAR_SKILLS[classId]]; +		skillStr = Common::String(skillP, skillP + NEW_CHAR_SKILLS_LEN[classId]); +	} + +	// If a class is provided, set the class name +	if (classId != -1) { +		classStr = Common::String::format("\t062\v168%s", CLASS_NAMES[classId]); +	} + +	// Set up default skill for the race, if any +	if (NEW_CHAR_RACE_SKILLS[race] != -1) { +		raceSkillStr = SKILL_NAMES[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(NEW_CHAR_STATS, RACE_NAMES[race], 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; +} + +/** + * Print the selection arrow to indicate the selected class + */ +void PartyDialog::printSelectionArrow(SpriteResource &icons, int selectedClass) { +	Window &w = _vm->_screen->_windows[0]; +	icons.draw(w, 61, Common::Point(220, 19)); +	icons.draw(w, 63, Common::Point(220, selectedClass * 11 + 21)); +	w.update(); +} + +/** + * Print the dice animation + */ +void PartyDialog::drawDice(SpriteResource &dice) { +	error("TODO: drawDice"); +} +  } // End of namespace Xeen diff --git a/engines/xeen/dialogs_party.h b/engines/xeen/dialogs_party.h index 1510b76093..e9b06ae732 100644 --- a/engines/xeen/dialogs_party.h +++ b/engines/xeen/dialogs_party.h @@ -56,6 +56,18 @@ private:  	void createChar();  	int selectCharacter(bool isDelete, int firstDisplayChar); + +	void throwDice(uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]); + +	void checkClass(const uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]); + +	int newCharDetails(const uint attribs[TOTAL_ATTRIBUTES],  +		bool allowedClasses[TOTAL_CLASSES], Race race, Sex sex, int classId, +		int selectedClass, Common::String &msg); + +	void printSelectionArrow(SpriteResource &icons, int selectedClass); + +	void drawDice(SpriteResource &dice);  public:  	static void show(XeenEngine *vm);  }; diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp index 8f1475308d..b11db9ff82 100644 --- a/engines/xeen/resources.cpp +++ b/engines/xeen/resources.cpp @@ -1450,4 +1450,25 @@ const char *const HAS_SLAYER_SWORD =  const char *const SURE_TO_DELETE_CHAR =   	"Are you sure you want to delete %s the %s?"; +const char *const CREATE_CHAR_DETAILS =  +	"\f04\x3""c\x2\t144\v119\f37R\f04oll\t144\v149\f37C\f04reate" +	"\t144\v179\f37ESC\f04\x3l\x1\t195\v021\f37M\f04gt" +	"\t195\v045\f37I\f04nt\t195\v069\f37P\f04er\t195\v093\f37E\f04nd" +	"\t195\v116\f37S\f04pd\t195\v140\f37A\f04cy\t195\v164\f37L\f04ck%s"; + +const char *const NEW_CHAR_STATS = +	"\f04\x3l\t022\v148Race\t055: %s\n" +	"\t022Sex\t055: %s\n" +	"\t022Class\t055:\n" +	"\x3r\t215\v031%d\t215\v055%d\t215\v079%d\t215\v103%d\t215\v127%d" +	"\t215\v151%d\t215\v175%d\x3l\t242\v020\f%2dKnight\t242\v031\f%2d" +	"Paladin\t242\v042\f%2dArcher\t242\v053\f%2dCleric\t242\v064\f%2d" +	"Sorcerer\t242\v075\f%2dRobber\t242\v086\f%2dNinja\t242\v097\f%2d" +	"Barbarian\t242\v108\f%2dDruid\t242\v119\f%2dRanger\f04\x3""c" +	"\t265\v142Skills\x3l\t223\v155%s\t223\v170%s%s"; + +const int NEW_CHAR_SKILLS[10] = { 1, 5, -1, -1, 4, 0, 0, -1, 6, 11 }; +const int NEW_CHAR_SKILLS_LEN[10] = { 11, 8, 0, 0, 12, 8, 8, 0, 9, 11 }; +const int NEW_CHAR_RACE_SKILLS[10] = { 14, -1, 17, 16, -1, 0, 0, 0, 0, 0 }; +  } // End of namespace Xeen diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h index 2ca9dbbfda..3c1ae9dbd0 100644 --- a/engines/xeen/resources.h +++ b/engines/xeen/resources.h @@ -504,6 +504,13 @@ extern const char *const YOUR_PARTY_IS_FULL;  extern const char *const HAS_SLAYER_SWORD;  extern const char *const SURE_TO_DELETE_CHAR; +extern const char *const CREATE_CHAR_DETAILS; + +extern const char *const NEW_CHAR_STATS; +extern const int NEW_CHAR_SKILLS[10]; +extern const int NEW_CHAR_SKILLS_LEN[10]; +extern const int NEW_CHAR_RACE_SKILLS[10]; +  } // End of namespace Xeen  #endif	/* XEEN_RESOURCES_H */ | 
