From 81e1bd2930bf4192fa8bfdbb805c65795e68c6e1 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 26 Jan 2015 21:35:50 -0500 Subject: XEEN: Implemented createTownText --- engines/xeen/party.cpp | 59 ++++++++++++++++ engines/xeen/party.h | 8 +++ engines/xeen/resources.cpp | 64 +++++++++++++++++ engines/xeen/resources.h | 24 +++++++ engines/xeen/town.cpp | 172 +++++++++++++++++++++++++++++++++++++++++++-- engines/xeen/town.h | 18 +++-- engines/xeen/xeen.cpp | 10 +++ engines/xeen/xeen.h | 4 ++ 8 files changed, 349 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/xeen/party.cpp b/engines/xeen/party.cpp index 388b8de261..1baa25404f 100644 --- a/engines/xeen/party.cpp +++ b/engines/xeen/party.cpp @@ -757,6 +757,65 @@ void Character::setValue(int id, uint value) { } } +bool Character::guildMember() const { + Party &party = *Party::_vm->_party; + + if (party._mazeId == 49 && !Party::_vm->_files->_isDarkCc) { + return hasAward(5); + } + + switch (party._mazeId) { + case 29: + return hasAward(83); + case 31: + return hasAward(84); + case 33: + return hasAward(85); + case 35: + return hasAward(86); + default: + return hasAward(87); + } +} + +uint Character::nextExperienceLevel() const { + uint base = currentExperienceLevel(); + uint curr = getCurrentExperience(); + return (curr < base) ? 0 : curr - base; +} + +uint Character::currentExperienceLevel() const { + int shift, base; + if (_level._permanent >= 12) { + base = _level._permanent - 12; + shift = 10; + } else { + base = 0; + shift = _level._permanent; + } + + return (base * 1024000) + (CLASS_EXP_LEVELS[_class] << shift); +} + +uint Character::getCurrentExperience() const { + int lev = _level._permanent - 1; + int shift, base; + + if (lev > 0 && lev < 12) + return _experience; + + if (lev >= 12) { + base = lev - 12; + shift = 10; + } else { + base = 0; + shift = lev - 1; + } + + return (base * 1024000) + (CLASS_EXP_LEVELS[_class] << shift) + + _experience; +} + /*------------------------------------------------------------------------*/ void Roster::synchronize(Common::Serializer &s) { diff --git a/engines/xeen/party.h b/engines/xeen/party.h index c77364bd10..0b7572cccf 100644 --- a/engines/xeen/party.h +++ b/engines/xeen/party.h @@ -167,6 +167,14 @@ public: int itemScan(int itemId) const; void setValue(int id, uint value); + + bool guildMember() const; + + uint nextExperienceLevel() const; + + uint currentExperienceLevel() const; + + uint getCurrentExperience() const; }; class Roster: public Common::Array { diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp index 9e11a17aa7..c1951d704c 100644 --- a/engines/xeen/resources.cpp +++ b/engines/xeen/resources.cpp @@ -290,6 +290,10 @@ const char *const CLASS_NAMES[11] = { "Ninja", "Barbarian", "Druid", "Ranger", nullptr }; +const uint CLASS_EXP_LEVELS[10] = { + 1500, 2000, 2000, 1500, 2000, 1000, 1500, 1500, 1500, 2000 +}; + const char *const CONDITION_NAMES[18] = { nullptr, "Cursed", "Heart Broken", "Weak", "Poisoned", "Diseased", "Insane", "In Love", "Drunk", "Asleep", "Depressed", "Confused", @@ -585,4 +589,64 @@ const int TOWN_ACTION_FILES[2][7] = { { 3, 2, 4, 2, 4, 2, 1 }, { 5, 3, 7, 5, 4, 6, 1 } }; +const char *const BANK_TEXT = "\x0D\x02\x03""c\x0B""122\x09""013" + "\x0C""37D\x0C""dep\x09""040\x0C""37W\x0C""dith\x09""067ESC" + "\x01\x09""000\x0B""000Bank of Xeen\x0B""015\n" + "Bank\x03l\n" + "Gold\x03r\x09""000%s\x03l\n" + "Gems\x03r\x09""000%s\x03""c\n" + "\n" + "Party\x03l\n" + "Gold\x03r\x09""000%s\x03l\n" + "Gems\x03r\x09""000%s"; + +const char *const BLACKSMITH_TEXT = "\x01\x0D\x03""c\x0B""000\x09""000" + "Store Options for\x09""039\x0B""027%s\x03""l\x0B""046\n" + "\x09""011\x0C""37B\x0C""drowse\n" + "\x09""000\x0B""090Gold\x03r\x09""000%s" + "\x02\x03""c\x0B""122\x09""040ESC\x01"; + +const char *const GUILD_NOT_MEMBER_TEXT = + "\n\nYou have to be a member to shop here."; + +const char *const GUILD_TEXT = "\x03""c\x0B""027\x09""039%s" + "\x03l\x0B""046\n" + "\x09""012\x0C""37B\x0C""duy Spells\n" + "\x09""012\x0C""37S\x0C""dpell Info"; + +const char *const TAVERN_TEXT = + "\x0D\x03""c\x0B""000\x09""000Tavern Options for\x09""039" + "\x0B""027%s%s\x03l\x09""000" + "\x0B""090Gold\x03r\x09""000%s\x02\x03""c\x0B""122" + "\x09""021\x0C""37S\x0C""dign in\x09""060ESC\x01"; + +const char *const FOOD_AND_DRINK = + "\x03l\x09""017\x0B""046\x0C""37D\x0C""drink\n" + "\x09""017\x0C""37F\x0C""dood\n" + "\x09""017\x0C""37T\x0C""dip\n" + "\x09""017\x0C""37R\x0C""dumors"; + +const char *const TEMPLE_TEXT = + "\x0D\x03""c\x0B""000\x09""000Temple Options for" + "\x09""039\x0B""027%s\x03l\x09""000\x0B""046" + "\x0C""37H\x0C""deal\x03r\x09""000%lu\x03l\n" + "\x0C""37D\x0C""donation\x03r\x09""000%lu\x03l\n" + "\x0C""37U\x0C""dnCurse\x03r\x09""000%s" + "\x03l\x09""000\x0B""090Gold\x03r\x09""000%s" + "\x02\x03""c\x0B""122\x09""040ESC\x01"; + +const char *const EXPERIENCE_FOR_LEVEL = + "%s needs %lu experience for level %u."; + +const char *const LEARNED_ALL = "%s has learned all we can teach!"; + +const char *const ELIGIBLE_FOR_LEVEL = "%s is eligible for level %d."; + +const char *const TRAINING_TEXT = + "\x0D\x03""cTraining Options\n" + "\n" + "%s\x03l\x0B""090\x09""000Gold\x03r\x09" + "000%s\x02\x03""c\x0B""122\x09""021" + "\x0C""37T\x0C""drain\x09""060ESC\x01"; + } // End of namespace Xeen diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h index ff192023a3..a6f52cb50e 100644 --- a/engines/xeen/resources.h +++ b/engines/xeen/resources.h @@ -66,6 +66,8 @@ extern const int RACE_SP_BONUSES[5][2]; extern const char *const CLASS_NAMES[11]; +extern const uint CLASS_EXP_LEVELS[10]; + extern const char *const ALIGNMENT_NAMES[3]; extern const char *const SEX_NAMES[2]; @@ -158,6 +160,28 @@ extern const char *const TOWN_ACTION_SHAPES[4]; extern const int TOWN_ACTION_FILES[2][7]; +extern const char *const BANK_TEXT; + +extern const char *const BLACKSMITH_TEXT; + +extern const char *const GUILD_NOT_MEMBER_TEXT; + +extern const char *const GUILD_TEXT; + +extern const char *const TAVERN_TEXT; + +extern const char *const FOOD_AND_DRINK; + +extern const char *const TEMPLE_TEXT; + +extern const char *const EXPERIENCE_FOR_LEVEL; + +extern const char *const LEARNED_ALL; + +extern const char *const ELIGIBLE_FOR_LEVEL; + +extern const char *const TRAINING_TEXT; + } // End of namespace Xeen #endif /* XEEN_RESOURCES_H */ diff --git a/engines/xeen/town.cpp b/engines/xeen/town.cpp index 214454b058..bb8590fc48 100644 --- a/engines/xeen/town.cpp +++ b/engines/xeen/town.cpp @@ -27,12 +27,23 @@ namespace Xeen { Town::Town(XeenEngine *vm) : _vm(vm) { + Common::fill(&_arr1[0], &_arr1[6], 0); _townMaxId = 0; _townActionId = 0; _townCurrent = 0; + _currentCharLevel = 0; _v1 = 0; _v2 = 0; - Common::fill(&_arr1[0], &_arr1[6], 0); + _donation = 0; + _healCost = 0; + _v5 = _v6 = 0; + _v10 = _v11 = 0; + _v12 = _v13 = 0; + _v14 = 0; + _v20 = 0; + _uncurseCost = 0; + _flag1 = false; + _nextExperienceLevel = 0; } void Town::loadStrings(const Common::String &name) { @@ -191,7 +202,8 @@ int Town::townAction(int actionId) { _townSprites[idx].load(shapesName); } - Common::String title = createTownText(); + Character *charP = &party._activeParty[0]; + Common::String title = createTownText(*charP); intf._face1UIFrame = intf._face2UIFrame = 0; intf._dangerSenseUIFrame = 0; intf._spotDoorsUIFrame = 0; @@ -222,7 +234,7 @@ int Town::townAction(int actionId) { do { townWait(); - doTownOptions(); + charP = doTownOptions(charP); screen._windows[10].writeString(title); drawButtons(&screen); } while (!_vm->shouldQuit() && _buttonValue != Common::KEYCODE_ESCAPE); @@ -309,11 +321,159 @@ void Town::dwarfEvent() { error("TODO: dwarfEvent"); } -Common::String Town::createTownText() { - error("TODO"); +Common::String Town::createTownText(Character &ch) { + Interface &intf = *_vm->_interface; + Party &party = *_vm->_party; + Common::String msg; + + switch (_townActionId) { + case 0: + // Bank + return Common::String::format(BANK_TEXT, + XeenEngine::printMil(party._bankGold).c_str(), + XeenEngine::printMil(party._bankGems).c_str(), + XeenEngine::printMil(party._gold).c_str(), + XeenEngine::printMil(party._gems).c_str()); + case 1: + // Blacksmith + return Common::String::format(BLACKSMITH_TEXT, + XeenEngine::printMil(party._gold)); + + case 2: + // Guild + return !ch.guildMember() ? GUILD_NOT_MEMBER_TEXT : + Common::String::format(GUILD_TEXT, ch._name.c_str()); + + case 3: + // Tavern + return Common::String::format(TAVERN_TEXT, ch._name, + FOOD_AND_DRINK, XeenEngine::printMil(party._gold).c_str()); + + case 4: + // Temple + _donation = 0; + _uncurseCost = 0; + _v5 = 0; + _v6 = 0; + _healCost = 0; + + if (party._mazeId == (_vm->_files->_isDarkCc ? 29 : 28)) { + _v10 = _v11 = _v12 = _v13 = 0; + _v14 = 10; + } else if (party._mazeId == (_vm->_files->_isDarkCc ? 31 : 30)) { + _v13 = 10; + _v12 = 50; + _v11 = 500; + _v10 = 100; + _v14 = 25; + } else if (party._mazeId == (_vm->_files->_isDarkCc ? 37 : 73)) { + _v13 = 20; + _v12 = 100; + _v11 = 1000; + _v10 = 200; + _v14 = 50; + } else if (_vm->_files->_isDarkCc || party._mazeId == 49) { + _v13 = 100; + _v12 = 500; + _v11 = 5000; + _v10 = 300; + _v14 = 100; + } + + _currentCharLevel = ch.getCurrentLevel(); + if (ch._currentHp < ch.getMaxHP()) { + _healCost = _currentCharLevel * 10 + _v13; + } + + for (int attrib = HEART_BROKEN; attrib <= UNCONSCIOUS; ++attrib) { + if (ch._conditions[attrib]) + _healCost += _currentCharLevel * 10; + } + + _v6 = 0; + if (ch._conditions[DEAD]) { + _v6 += (_currentCharLevel * 100) + (ch._conditions[DEAD] * 50) + _v12; + } + if (ch._conditions[STONED]) { + _v6 += (_currentCharLevel * 100) + (ch._conditions[STONED] * 50) + _v12; + } + if (ch._conditions[ERADICATED]) { + _v5 = (_currentCharLevel * 1000) + (ch._conditions[ERADICATED] * 500) + _v11; + } + + for (int idx = 0; idx < 9; ++idx) { + _uncurseCost |= ch._weapons[idx]._bonusFlags & 0x40; + _uncurseCost |= ch._armor[idx]._bonusFlags & 0x40; + _uncurseCost |= ch._accessories[idx]._bonusFlags & 0x40; + _uncurseCost |= ch._misc[idx]._bonusFlags & 0x40; + } + + if (_uncurseCost || ch._conditions[CURSED]) + _v5 = (_currentCharLevel * 20) + _v10; + + _donation = _flag1 ? 0 : _v14; + _healCost += _v6 + _v5; + + return Common::String::format(TEMPLE_TEXT, ch._name.c_str(), + _healCost, _donation, XeenEngine::printK(_uncurseCost).c_str(), + XeenEngine::printMil(party._gold).c_str()); + + case 5: + // Training + if (_vm->_files->_isDarkCc) { + switch (party._mazeId) { + case 29: + _v20 = 30; + break; + case 31: + _v20 = 50; + break; + case 37: + _v20 = 200; + break; + default: + _v20 = 100; + break; + } + } else { + switch (party._mazeId) { + case 28: + _v20 = 10; + break; + case 30: + _v20 = 15; + break; + default: + _v20 = 20; + break; + } + } + + _nextExperienceLevel = ch.nextExperienceLevel(); + + if (_nextExperienceLevel >= 0x10000 && ch._level._permanent < _v20) { + int nextLevel = ch._level._permanent + 1; + return Common::String::format(EXPERIENCE_FOR_LEVEL, + ch._name.c_str(), _nextExperienceLevel, nextLevel); + } else if (ch._level._permanent >= 20) { + _nextExperienceLevel = 1; + msg = Common::String::format(LEARNED_ALL, ch._name.c_str()); + } else { + msg = Common::String::format(ELIGIBLE_FOR_LEVEL, + ch._name.c_str(), ch._level._permanent + 1); + } + + return Common::String::format(TRAINING_TEXT, + XeenEngine::printMil(party._gold).c_str()); + + default: + return ""; + } } -void Town::doTownOptions() { +Character *Town::doTownOptions(Character *charP) { + Common::String result; + error("TODO: doTownOptions"); } diff --git a/engines/xeen/town.h b/engines/xeen/town.h index 2221ed5400..07e9badc46 100644 --- a/engines/xeen/town.h +++ b/engines/xeen/town.h @@ -26,6 +26,7 @@ #include "common/scummsys.h" #include "common/str-array.h" #include "xeen/dialogs.h" +#include "xeen/party.h" namespace Xeen { @@ -40,10 +41,19 @@ private: int _townMaxId; int _townActionId; int _townCurrent; - int _v1; - int _v2; + int _v1, _v2; + int _donation; + int _healCost; + int _v5, _v6; + int _v10, _v11, _v12; + int _v13, _v14; + int _v20; + int _uncurseCost; Common::Point _townPos; int _arr1[6]; + int _currentCharLevel; + bool _flag1; + uint _nextExperienceLevel; void loadStrings(const Common::String &name); @@ -59,11 +69,11 @@ private: void dwarfEvent(); - Common::String createTownText(); + Common::String createTownText(Character &ch); void townWait(); - void doTownOptions(); + Character *doTownOptions(Character *charP); public: Town(XeenEngine *vm); diff --git a/engines/xeen/xeen.cpp b/engines/xeen/xeen.cpp index 8d646fbcf5..d7a85fbbf8 100644 --- a/engines/xeen/xeen.cpp +++ b/engines/xeen/xeen.cpp @@ -339,4 +339,14 @@ void XeenEngine::gameLoop() { } } +Common::String XeenEngine::printMil(uint value) { + return (value >= 1000000) ? Common::String::format("%lu mil", value / 1000000) : + Common::String::format("%lu", value); +} + +Common::String XeenEngine::printK(uint value) { + return (value > 9999) ? Common::String::format("%uk", value / 1000) : + Common::String::format("%u", value); +} + } // End of namespace Xeen diff --git a/engines/xeen/xeen.h b/engines/xeen/xeen.h index 1145072d6d..cb09c280cd 100644 --- a/engines/xeen/xeen.h +++ b/engines/xeen/xeen.h @@ -198,6 +198,10 @@ public: * Write out a savegame header */ void writeSavegameHeader(Common::OutSaveFile *out, XeenSavegameHeader &header); + + static Common::String printMil(uint value); + + static Common::String printK(uint value); }; } // End of namespace Xeen -- cgit v1.2.3