diff options
-rw-r--r-- | COPYRIGHT | 2 | ||||
-rw-r--r-- | backends/platform/symbian/README | 2 | ||||
-rw-r--r-- | dists/macosx/Info.plist | 4 | ||||
-rw-r--r-- | dists/macosx/Info.plist.in | 4 | ||||
-rw-r--r-- | dists/macosx/dockplugin/Info.plist | 2 | ||||
-rw-r--r-- | dists/macosx/dockplugin/Info.plist.in | 2 | ||||
-rw-r--r-- | dists/scummvm.rc | 2 | ||||
-rw-r--r-- | dists/scummvm.rc.in | 2 | ||||
-rw-r--r-- | dists/win32/ScummVM.iss | 2 | ||||
-rw-r--r-- | dists/win32/migration.bat | 2 | ||||
-rw-r--r-- | engines/mohawk/riven_video.cpp | 1 | ||||
-rw-r--r-- | engines/xeen/character.cpp | 163 | ||||
-rw-r--r-- | engines/xeen/character.h | 102 | ||||
-rw-r--r-- | engines/xeen/dialogs.cpp | 8 | ||||
-rw-r--r-- | engines/xeen/dialogs.h | 7 | ||||
-rw-r--r-- | engines/xeen/dialogs_awards.cpp | 2 | ||||
-rw-r--r-- | engines/xeen/dialogs_input.cpp | 4 | ||||
-rw-r--r-- | engines/xeen/dialogs_party.cpp | 2 | ||||
-rw-r--r-- | engines/xeen/locations.cpp | 3 | ||||
-rw-r--r-- | engines/xeen/party.cpp | 27 | ||||
-rw-r--r-- | engines/xeen/resources.cpp | 2 | ||||
-rw-r--r-- | engines/xeen/scripts.cpp | 95 | ||||
-rw-r--r-- | engines/xeen/scripts.h | 6 | ||||
-rw-r--r-- | graphics/VectorRendererSpec.cpp | 136 | ||||
-rw-r--r-- | gui/about.cpp | 2 |
25 files changed, 350 insertions, 234 deletions
@@ -1,5 +1,5 @@ ScummVM -Copyright (C) 2001-2017 by the following: +Copyright (C) 2001-2018 by the following: If you have contributed to this project then you deserve to be on this list. Contact us (see: AUTHORS) and we'll add you. diff --git a/backends/platform/symbian/README b/backends/platform/symbian/README index cdff5f9787..867a683f41 100644 --- a/backends/platform/symbian/README +++ b/backends/platform/symbian/README @@ -1,7 +1,7 @@ ScummVM - ScummVM ported to EPOC/SymbianOS - Copyright (C) 2008-2017 ScummVM Team + Copyright (C) 2008-2018 ScummVM Team Copyright (C) 2013-2013 Fedor Strizhniou aka zanac Copyright (C) 2003-2013 Lars 'AnotherGuest' Persson Copyright (C) 2002-2008 Jurgen 'SumthinWicked' Braam diff --git a/dists/macosx/Info.plist b/dists/macosx/Info.plist index f61bb3b462..db46156d68 100644 --- a/dists/macosx/Info.plist +++ b/dists/macosx/Info.plist @@ -9,7 +9,7 @@ <key>CFBundleExecutable</key> <string>scummvm</string> <key>CFBundleGetInfoString</key> - <string>2.1.0git, Copyright 2001-2017 The ScummVM Team</string> + <string>2.1.0git, Copyright 2001-2018 The ScummVM Team</string> <key>CFBundleIconFile</key> <string>scummvm.icns</string> <key>CFBundleIdentifier</key> @@ -49,7 +49,7 @@ <key>CFBundleVersion</key> <string>2.1.0git</string> <key>NSHumanReadableCopyright</key> - <string>Copyright 2001-2017 The ScummVM Team</string> + <string>Copyright 2001-2018 The ScummVM Team</string> <key>NSPrincipalClass</key> <string>NSApplication</string> <key>SUFeedURL</key> diff --git a/dists/macosx/Info.plist.in b/dists/macosx/Info.plist.in index db740769ef..93ab74b1e8 100644 --- a/dists/macosx/Info.plist.in +++ b/dists/macosx/Info.plist.in @@ -9,7 +9,7 @@ <key>CFBundleExecutable</key> <string>scummvm</string> <key>CFBundleGetInfoString</key> - <string>@VERSION@, Copyright 2001-2017 The ScummVM Team</string> + <string>@VERSION@, Copyright 2001-2018 The ScummVM Team</string> <key>CFBundleIconFile</key> <string>scummvm.icns</string> <key>CFBundleIdentifier</key> @@ -49,7 +49,7 @@ <key>CFBundleVersion</key> <string>@VERSION@</string> <key>NSHumanReadableCopyright</key> - <string>Copyright 2001-2017 The ScummVM Team</string> + <string>Copyright 2001-2018 The ScummVM Team</string> <key>NSPrincipalClass</key> <string>NSApplication</string> <key>SUFeedURL</key> diff --git a/dists/macosx/dockplugin/Info.plist b/dists/macosx/dockplugin/Info.plist index f030b60b9b..6e68bc4edb 100644 --- a/dists/macosx/dockplugin/Info.plist +++ b/dists/macosx/dockplugin/Info.plist @@ -19,7 +19,7 @@ <key>CFBundleVersion</key> <string>2.1.0git</string> <key>NSHumanReadableCopyright</key> - <string>Copyright 2001-2017 The ScummVM Team</string> + <string>Copyright 2001-2018 The ScummVM Team</string> <key>NSPrincipalClass</key> <string>ScummVMDockTilePlugIn</string> </dict> diff --git a/dists/macosx/dockplugin/Info.plist.in b/dists/macosx/dockplugin/Info.plist.in index 57699e6151..60a03aecac 100644 --- a/dists/macosx/dockplugin/Info.plist.in +++ b/dists/macosx/dockplugin/Info.plist.in @@ -19,7 +19,7 @@ <key>CFBundleVersion</key> <string>@VERSION@</string> <key>NSHumanReadableCopyright</key> - <string>Copyright 2001-2017 The ScummVM Team</string> + <string>Copyright 2001-2018 The ScummVM Team</string> <key>NSPrincipalClass</key> <string>ScummVMDockTilePlugIn</string> </dict> diff --git a/dists/scummvm.rc b/dists/scummvm.rc index 2cdeeb8227..a5b6eb222b 100644 --- a/dists/scummvm.rc +++ b/dists/scummvm.rc @@ -94,7 +94,7 @@ BEGIN VALUE "FileDescription", "http://www.scummvm.org/\0" VALUE "FileVersion", "2.1.0git\0" VALUE "InternalName", "scummvm\0" - VALUE "LegalCopyright", "Copyright © 2001-2017 The ScummVM Team\0" + VALUE "LegalCopyright", "Copyright © 2001-2018 The ScummVM Team\0" VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0" VALUE "OriginalFilename", "scummvm.exe\0" VALUE "ProductName", "ScummVM\0" diff --git a/dists/scummvm.rc.in b/dists/scummvm.rc.in index 3aa95b3671..d960cc2a75 100644 --- a/dists/scummvm.rc.in +++ b/dists/scummvm.rc.in @@ -94,7 +94,7 @@ BEGIN VALUE "FileDescription", "http://www.scummvm.org/\0" VALUE "FileVersion", "@VERSION@\0" VALUE "InternalName", "scummvm\0" - VALUE "LegalCopyright", "Copyright © 2001-2017 The ScummVM Team\0" + VALUE "LegalCopyright", "Copyright © 2001-2018 The ScummVM Team\0" VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0" VALUE "OriginalFilename", "scummvm.exe\0" VALUE "ProductName", "ScummVM\0" diff --git a/dists/win32/ScummVM.iss b/dists/win32/ScummVM.iss index 8a495e0b45..4fcc4f7ee4 100644 --- a/dists/win32/ScummVM.iss +++ b/dists/win32/ScummVM.iss @@ -1,5 +1,5 @@ [Setup] -AppCopyright=2017 +AppCopyright=2018 AppName=ScummVM AppVerName=ScummVM Git AppPublisher=The ScummVM Team diff --git a/dists/win32/migration.bat b/dists/win32/migration.bat index 6ec7806b5f..95f554af2b 100644 --- a/dists/win32/migration.bat +++ b/dists/win32/migration.bat @@ -4,7 +4,7 @@ :: This script will copy any saved games located in the :: old default location, to the new default location. :: -:: (c) 2012-2017 ScummVM Team +:: (c) 2012-2018 ScummVM Team :: @echo off diff --git a/engines/mohawk/riven_video.cpp b/engines/mohawk/riven_video.cpp index 14af3e566b..9bd185ed5d 100644 --- a/engines/mohawk/riven_video.cpp +++ b/engines/mohawk/riven_video.cpp @@ -255,6 +255,7 @@ void RivenVideo::playBlocking(int32 endTime) { if (playTillEnd) { disable(); stop(); + seek(0); } // Execute the stored opcode diff --git a/engines/xeen/character.cpp b/engines/xeen/character.cpp index 8a6dd14c42..7e36e54190 100644 --- a/engines/xeen/character.cpp +++ b/engines/xeen/character.cpp @@ -61,6 +61,25 @@ AttributeCategory XeenItem::getAttributeCategory() const { return (AttributeCategory)idx; } +const char *XeenItem::getItemName(ItemCategory category, uint id) { + if (id < 82) + return Res.ITEM_NAMES[category][id]; + + switch (category) { + case CATEGORY_WEAPON: + return Res.QUEST_ITEM_NAMES[id - 82]; + + case CATEGORY_ARMOR: + return Res.QUEST_ITEM_NAMES[id - 82 + 35]; + + case CATEGORY_ACCESSORY: + return Res.QUEST_ITEM_NAMES[id - 82 + 35 + 14]; + + default: + return Res.QUEST_ITEM_NAMES[id - 82 + 35 + 14 + 11]; + } +} + /*------------------------------------------------------------------------*/ InventoryItems::InventoryItems(Character *character, ItemCategory category): @@ -1106,87 +1125,80 @@ uint Character::getCurrentLevel() const { int Character::itemScan(int itemId) const { int result = 0; - for (int accessIdx = 0; accessIdx < 3; ++accessIdx) { - switch (accessIdx) { - case 0: - for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) { - const XeenItem &item = _weapons[idx]; + // Weapons + for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) { + const XeenItem &item = _weapons[idx]; - if (item._frame && !(item._bonusFlags & 0xC0) && itemId < 11 - && itemId != 3 && item._material >= 59 && item._material <= 130) { - int mIndex = (int)item.getAttributeCategory(); - if (mIndex > PERSONALITY) - ++mIndex; + if (item._frame && !(item._bonusFlags & 0xC0) && itemId < 11 + && itemId != 3 && item._material >= 59 && item._material <= 130) { + int mIndex = (int)item.getAttributeCategory(); + if (mIndex > PERSONALITY) + ++mIndex; - if (mIndex == itemId) - result += Res.ATTRIBUTE_BONUSES[item._material - 59]; - } + if (mIndex == itemId) + result += Res.ATTRIBUTE_BONUSES[item._material - 59]; + } + } + + // Armor + for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) { + const XeenItem &item = _armor[idx]; + + if (item._frame && !(item._bonusFlags & 0xC0)) { + if (itemId < 11 && itemId != 3 && item._material >= 59 && item._material <= 130) { + int mIndex = (int)item.getAttributeCategory(); + if (mIndex > PERSONALITY) + ++mIndex; + + if (mIndex == itemId) + result += Res.ATTRIBUTE_BONUSES[item._material - 59]; } - break; - case 1: - for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) { - const XeenItem &item = _armor[idx]; + if (itemId > 10 && item._material < 37) { + int mIndex = item.getElementalCategory() + 11; - if (item._frame && !(item._bonusFlags & 0xC0)) { - if (itemId < 11 && itemId != 3 && item._material >= 59 && item._material <= 130) { - int mIndex = (int)item.getAttributeCategory(); - if (mIndex > PERSONALITY) - ++mIndex; + if (mIndex == itemId) { + result += Res.ELEMENTAL_RESISTENCES[item._material]; + } + } - if (mIndex == itemId) - result += Res.ATTRIBUTE_BONUSES[item._material - 59]; - } + if (itemId == 9) { + result += Res.ARMOR_STRENGTHS[item._id]; - if (itemId > 10 && item._material < 37) { - int mIndex = item.getElementalCategory() + 11; + if (item._material >= 37 && item._material <= 58) + result += Res.METAL_LAC[item._material - 37]; + } + } + } - if (mIndex == itemId) { - result += Res.ELEMENTAL_RESISTENCES[item._material]; - } - } + // Accessories + for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) { + const XeenItem &item = _accessories[idx]; - if (itemId == 9) { - result += Res.ARMOR_STRENGTHS[item._id]; + if (item._frame && !(item._bonusFlags & 0xC0)) { + if (itemId < 11 && itemId != 3 && item._material >= 59 && item._material <= 130) { + int mIndex = (int)item.getAttributeCategory(); + if (mIndex > PERSONALITY) + ++mIndex; - if (item._material >= 37 && item._material <= 58) - result += Res.METAL_LAC[item._material - 37]; - } + if (mIndex == itemId) { + result += Res.ATTRIBUTE_BONUSES[item._material - 59]; } } - break; - case 2: - for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) { - const XeenItem &item = _accessories[idx]; - - if (item._frame && !(item._bonusFlags & 0xC0)) { - if (itemId < 11 && itemId != 3 && item._material >= 59 && item._material <= 130) { - int mIndex = (int)item.getAttributeCategory(); - if (mIndex > PERSONALITY) - ++mIndex; - - if (mIndex == itemId) { - result += Res.ATTRIBUTE_BONUSES[item._material - 59]; - } - } - - if (itemId > 10 && item._material < 37) { - int mIndex = item.getElementalCategory() + 11; - - if (mIndex == itemId) - result += Res.ELEMENTAL_RESISTENCES[item._material]; - } - - if (itemId == 9) { - result += Res.ARMOR_STRENGTHS[item._id]; - if (item._material >= 37 && item._material <= 58) { - result += Res.METAL_LAC[item._material - 37]; - } - } + if (itemId > 10 && item._material < 37) { + int mIndex = item.getElementalCategory() + 11; + + if (mIndex == itemId) + result += Res.ELEMENTAL_RESISTENCES[item._material]; + } + + if (itemId == 9) { + result += Res.ARMOR_STRENGTHS[item._id]; + if (item._material >= 37 && item._material <= 58) { + result += Res.METAL_LAC[item._material - 37]; } } - break; } } @@ -1439,23 +1451,24 @@ void Character::setValue(int id, uint value) { } bool Character::guildMember() const { - Party &party = *Party::_vm->_party; + FileManager &files = *g_vm->_files; + Party &party = *g_vm->_party; - if (party._mazeId == 49 && !Party::_vm->_files->_isDarkCc) { - return hasAward(5); + if (party._mazeId == 49 && !files._isDarkCc) { + return hasAward(SHANGRILA_GUILD_MEMBER); } switch (party._mazeId) { case 29: - return hasAward(83); + return hasAward(CASTLEVIEW_GUILD_MEMBER); case 31: - return hasAward(84); + return hasAward(SANDCASTER_GUILD_MEMBER); case 33: - return hasAward(85); + return hasAward(LAKESIDE_GUILD_MEMBER); case 35: - return hasAward(86); + return hasAward(NECROPOLIS_GUILD_MEMBER); default: - return hasAward(87); + return hasAward(OLYMPUS_GUILD_MEMBER); } } @@ -1806,7 +1819,7 @@ void Character::subtractHitPoints(int amount) { } } -bool Character::hasSpecialItem() const { +bool Character::hasSlayerSword() const { for (uint idx = 0; idx < INV_ITEMS_TOTAL; ++idx) { if (_weapons[idx]._id == 34) // Character has Xeen Slayer sword diff --git a/engines/xeen/character.h b/engines/xeen/character.h index c19cfef4fc..54e8d1a37c 100644 --- a/engines/xeen/character.h +++ b/engines/xeen/character.h @@ -37,6 +37,12 @@ namespace Xeen { #define AWARDS_TOTAL 88 #define WARZONE_AWARD 9 +enum Award { + SHANGRILA_GUILD_MEMBER = 5, GOOBER = 76, SUPER_GOOBER = 77, + CASTLEVIEW_GUILD_MEMBER = 83, SANDCASTER_GUILD_MEMBER = 84, + LAKESIDE_GUILD_MEMBER = 85, NECROPOLIS_GUILD_MEMBER = 86, OLYMPUS_GUILD_MEMBER = 87 +}; + enum BonusFlags { ITEMFLAG_BONUS_MASK = 0xBF, ITEMFLAG_CURSED = 0x40, ITEMFLAG_BROKEN = 0x80 }; @@ -97,16 +103,36 @@ public: int _bonusFlags; int _frame; public: + /** + * Return the name of the item + */ + static const char *getItemName(ItemCategory category, uint id); +public: XeenItem(); + /** + * Clear the data for the item + */ void clear(); + /** + * Returns true if no item is set + */ bool empty() const { return _id != 0; } + /** + * Synchronizes the data for the item + */ void synchronize(Common::Serializer &s); + /** + * Gets the elemental category for the item + */ ElementalCategory getElementalCategory() const; + /** + * Gets the attribute category for the item + */ AttributeCategory getAttributeCategory() const; }; @@ -125,6 +151,9 @@ public: InventoryItems(Character *character, ItemCategory category); virtual ~InventoryItems() {} + /** + * Clears the set of items + */ void clear(); /** @@ -139,6 +168,9 @@ public: virtual Common::String getFullDescription(int itemIndex, int displayNum = 15) = 0; + /** + * Returns the identified details for an item + */ Common::String getIdentifiedDetails(int itemIndex); /** @@ -146,6 +178,9 @@ public: */ bool discardItem(int itemIndex); + /** + * Equips an item + */ virtual void equipItem(int itemIndex) {} /** @@ -158,6 +193,9 @@ public: */ void sort(); + /** + * Enchants an item + */ virtual void enchantItem(int itemIndex, int amount); /** @@ -184,6 +222,9 @@ public: */ virtual Common::String getFullDescription(int itemIndex, int displayNum); + /** + * Enchants a weapon + */ virtual void enchantItem(int itemIndex, int amount); }; @@ -205,6 +246,9 @@ public: */ virtual Common::String getFullDescription(int itemIndex, int displayNum); + /** + * Enchants an armor + */ virtual void enchantItem(int itemIndex, int amount); }; @@ -323,8 +367,14 @@ public: public: Character(); + /** + * Clears the data for a character + */ void clear(); + /** + * Synchronizes data for the character + */ void synchronize(Common::Serializer &s); /** @@ -352,8 +402,14 @@ public: */ int getAge(bool ignoreTemp = false) const; + /** + * Gets the maximum hit points for a character + */ int getMaxHP() const; + /** + * Gets the maximum spell points for a character + */ int getMaxSP() const; /** @@ -367,10 +423,19 @@ public: */ static int statColor(int amount, int threshold); + /** + * Returns the bonus the character gets for stats + */ int statBonus(uint statValue) const; + /** + * Returns true if the character passes a saving throw for a given attack type + */ bool charSavingThrow(DamageType attackType) const; + /** + * Returns true if the character is unable to perform any action + */ bool noActions(); /** @@ -383,6 +448,9 @@ public: */ bool hasAward(int awardId) const; + /** + * Returns the character's armor class + */ int getArmorClass(bool baseOnly = false) const; /** @@ -392,16 +460,34 @@ public: uint getCurrentLevel() const; + /** + * Scans the character's inventory for the given item + */ int itemScan(int itemId) const; + /** + * Sets various attributes of a character + */ void setValue(int id, uint value); + /** + * Returns true if the character is a member of the current town's guild + */ bool guildMember() const; + /** + * Returns the experience required to reach the next level + */ uint experienceToNextLevel() const; + /** + * Returns the next level the character will reach + */ uint nextExperienceLevel() const; + /** + * Returns the character's current experience + */ uint getCurrentExperience() const; /** @@ -414,6 +500,9 @@ public: */ int getNumAwards() const; + /** + * Creates an item and adds it to the inventory + */ int makeItem(int p1, int itemIndex, int p3); /** @@ -422,14 +511,23 @@ public: void addHitPoints(int amount); /** - * Remove hit points fromo the character + * Remove hit points from the character */ void subtractHitPoints(int amount); - bool hasSpecialItem() const; + /** + * Returns true if the character has the Xeen Slayer Sword + */ + bool hasSlayerSword() const; + /** + * Returns true if the character has a missile weapon, such as a bow + */ bool hasMissileWeapon() const; + /** + * Returns a category index for a character, used such for indexing into spell data + */ int getClassCategory() const; }; diff --git a/engines/xeen/dialogs.cpp b/engines/xeen/dialogs.cpp index 3062bec908..04d56d72bf 100644 --- a/engines/xeen/dialogs.cpp +++ b/engines/xeen/dialogs.cpp @@ -160,6 +160,14 @@ void ButtonContainer::loadStrings(const Common::String &name) { f.close(); } +void ButtonContainer::loadStrings(const Common::String &name, int ccMode) { + File f(name, ccMode); + _textStrings.clear(); + while (f.pos() < f.size()) + _textStrings.push_back(f.readString()); + f.close(); +} + /*------------------------------------------------------------------------*/ void SettingsBaseDialog::showContents(SpriteResource &title1, bool waitFlag) { diff --git a/engines/xeen/dialogs.h b/engines/xeen/dialogs.h index 92e2d3ba6d..d0bf20108b 100644 --- a/engines/xeen/dialogs.h +++ b/engines/xeen/dialogs.h @@ -70,6 +70,13 @@ protected: * @param name Name of resource containing strings */ void loadStrings(const Common::String &name); + + /** + * Load a set of text strings from the given resource + * @param name Name of resource containing strings + * @param ccMode Optional cc file number to explicitly use + */ + void loadStrings(const Common::String &name, int ccMode); public: ButtonContainer(XeenEngine *vm) : Cutscenes(vm), _buttonValue(0) {} diff --git a/engines/xeen/dialogs_awards.cpp b/engines/xeen/dialogs_awards.cpp index 91421cab16..ab1b79193b 100644 --- a/engines/xeen/dialogs_awards.cpp +++ b/engines/xeen/dialogs_awards.cpp @@ -41,7 +41,7 @@ void Awards::execute(const Character *ch) { Mode oldMode = g_vm->_mode; int topIndex = 0; - loadStrings("award.bin"); + loadStrings("award.bin", 1); addButtons(); // Open the window and draw contents diff --git a/engines/xeen/dialogs_input.cpp b/engines/xeen/dialogs_input.cpp index 8346c8e47b..6437778f7c 100644 --- a/engines/xeen/dialogs_input.cpp +++ b/engines/xeen/dialogs_input.cpp @@ -144,6 +144,7 @@ int StringInput::show(XeenEngine *vm, bool type, const Common::String &msg1, int StringInput::execute(bool type, const Common::String &expected, const Common::String &title, int opcode) { + FileManager &files = *_vm->_files; Interface &intf = *_vm->_interface; Scripts &scripts = *_vm->_scripts; Windows &windows = *_vm->_windows; @@ -165,8 +166,7 @@ int StringInput::execute(bool type, const Common::String &expected, } } else { // Load in the mirror list - File f(Common::String::format("%smirr.txt", - _vm->_files->_isDarkCc ? "dark" : "xeen")); + File f(Common::String::format("%smirr.txt", files._isDarkCc ? "dark" : "xeen"), 1); MirrorEntry me; scripts._mirror.clear(); while (me.synchronize(f)) diff --git a/engines/xeen/dialogs_party.cpp b/engines/xeen/dialogs_party.cpp index 39b4615ad5..f4d95ca612 100644 --- a/engines/xeen/dialogs_party.cpp +++ b/engines/xeen/dialogs_party.cpp @@ -222,7 +222,7 @@ void PartyDialog::execute() { if (charButtonValue != 0) { int charIndex = charButtonValue - Common::KEYCODE_1 + startingChar; Character &c = party._roster[_charList[charIndex]]; - if (c.hasSpecialItem()) { + if (c.hasSlayerSword()) { ErrorScroll::show(_vm, Res.HAS_SLAYER_SWORD); } else { Common::String msg = Common::String::format(Res.SURE_TO_DELETE_CHAR, diff --git a/engines/xeen/locations.cpp b/engines/xeen/locations.cpp index 392b7007cd..11391736d5 100644 --- a/engines/xeen/locations.cpp +++ b/engines/xeen/locations.cpp @@ -2409,8 +2409,7 @@ bool LocationMessage::execute(int portrait, const Common::String &name, const Co if (!msgEnd && !confirm) { res._globalSprites.draw(0, 7, Common::Point(232, 74)); - res._globalSprites.draw(0, 0, Common::Point(235, 75)); - res._globalSprites.draw(0, 2, Common::Point(260, 75)); + drawButtons(&windows[0]); windows[34].update(); intf._face1State = map._headData[party._mazePosition.y][party._mazePosition.x]._left; diff --git a/engines/xeen/party.cpp b/engines/xeen/party.cpp index 49369e74be..49d86bee62 100644 --- a/engines/xeen/party.cpp +++ b/engines/xeen/party.cpp @@ -574,7 +574,7 @@ void Party::giveTreasure() { Windows &windows = *_vm->_windows; Window &w = windows[10]; - if (!_treasure._gold && !_treasure._gems) + if (!_treasure._hasItems && !_treasure._gold && !_treasure._gems) return; bool monstersPresent = false; @@ -652,7 +652,7 @@ void Party::giveTreasure() { Character &c = _activeParty[charIndex]; if (!c._items[(ItemCategory)categoryNum].isFull() && !c.isDisabledOrDead()) { giveTreasureToCharacter(c, (ItemCategory)categoryNum, itemNum); - continue; + break; } } } @@ -713,17 +713,15 @@ void Party::giveTreasureToCharacter(Character &c, ItemCategory category, int ite if (treasureItem._id < 82) { // Copy item into the character's inventory c._items[category][INV_ITEMS_TOTAL - 1] = treasureItem; - c._items[category].sort(); } w.writeString(Res.GIVE_TREASURE_FORMATTING); w.update(); events.ipause(5); - w.writeString(Common::String::format(Res.X_FOUND_Y, c._name.c_str(), - Res.ITEM_NAMES[category][treasureItem._id])); + const char *itemName = XeenItem::getItemName(category, treasureItem._id); + w.writeString(Common::String::format(Res.X_FOUND_Y, c._name.c_str(), itemName)); w.update(); - events.ipause(5); } @@ -1100,7 +1098,10 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int break; case 21: { int idx; - if (giveVal < 35) { + if (giveVal >= 82) { + _questItems[giveVal - 82]++; + } + if (giveVal < 35 || giveVal >= 82) { for (idx = 0; idx < 10 && _treasure._weapons[idx]._id; ++idx); if (idx < 10) { _treasure._weapons[idx]._id = giveVal; @@ -1121,15 +1122,13 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int _treasure._hasItems = true; return false; } - } else if (giveVal < 82) { + } else { for (idx = 0; idx < 10 && _treasure._misc[idx]._material; ++idx); if (idx < 10) { _treasure._accessories[idx]._material = giveVal - 60; _treasure._hasItems = true; return false; } - } else { - _questItems[giveVal - 82]++; } return true; } @@ -1400,8 +1399,6 @@ bool Party::giveExt(int mode1, uint val1, int mode2, uint val2, int mode3, uint Scripts &scripts = *g_vm->_scripts; Sound &sound = *g_vm->_sound; Character &c = party._activeParty[charId]; - int var1 = 0; - bool retFlag = false; if (intf._objNumber && !scripts._animCounter) { MazeObject &obj = map._mobData._objects[intf._objNumber - 1]; @@ -1428,6 +1425,7 @@ bool Party::giveExt(int mode1, uint val1, int mode2, uint val2, int mode3, uint g_vm->_mode = MODE_7; c._experience += c.getCurrentLevel() * unlockBox * 10; + sound.playFX(10); intf.draw3d(true, false); Common::String msg = Common::String::format(Res.PICKS_THE_LOCK, c._name.c_str()); ErrorScroll::show(g_vm, msg); @@ -1480,13 +1478,10 @@ bool Party::giveExt(int mode1, uint val1, int mode2, uint val2, int mode3, uint break; case 67: - retFlag = true; - // Intentional fall-through - default: if (giveTake(0, 0, mode, val, charId)) return true; - else if (retFlag) + else if (mode == 67) return false; break; } diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp index 7edd920db0..f9b6548404 100644 --- a/engines/xeen/resources.cpp +++ b/engines/xeen/resources.cpp @@ -1581,7 +1581,7 @@ const char *const Resources::BACKPACKS_FULL_PRESS_KEY = "\v007\f12Warning! BackPacks Full!\fd\n" "Press a Key"; -const char *const Resources::HIT_A_KEY = "\x3l\v120\t000\x4""077\x3""c\f37Hit a key\f'd"; +const char *const Resources::HIT_A_KEY = "\x3l\v120\t000\x4""077\x3""c\f37Hit a key\xC""d"; const char *const Resources::GIVE_TREASURE_FORMATTING = "\x3l\v060\t000\x4""077\n" diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp index fde53b0091..99603224c8 100644 --- a/engines/xeen/scripts.cpp +++ b/engines/xeen/scripts.cpp @@ -348,7 +348,7 @@ bool Scripts::doOpcode(MazeEvent &event) { &Scripts::cmdMoveObj, &Scripts::cmdTakeOrGive, &Scripts::cmdDoNothing, &Scripts::cmdRemove, &Scripts::cmdSetChar, &Scripts::cmdSpawn, &Scripts::cmdDoTownEvent, &Scripts::cmdExit, &Scripts::cmdAlterMap, - &Scripts::cmdGiveExtended, &Scripts::cmdConfirmWord, &Scripts::cmdDamage, + &Scripts::cmdGiveMulti, &Scripts::cmdConfirmWord, &Scripts::cmdDamage, &Scripts::cmdJumpRnd, &Scripts::cmdAlterEvent, &Scripts::cmdCallEvent, &Scripts::cmdReturn, &Scripts::cmdSetVar, &Scripts::cmdTakeOrGive, &Scripts::cmdTakeOrGive, &Scripts::cmdCutsceneEndClouds, @@ -468,7 +468,8 @@ bool Scripts::cmdTeleport(ParamsIterator ¶ms) { Sound &sound = *_vm->_sound; windows.closeAll(); - + + bool restartFlag = _event->_opcode == OP_TeleportAndContinue; int mapId = params.readByte(); Common::Point pt; @@ -519,11 +520,13 @@ bool Scripts::cmdTeleport(ParamsIterator ¶ms) { events.clearEvents(); - if (_event->_opcode == OP_TeleportAndContinue) { + if (restartFlag) { + // Draw the new location and start any script at that location intf.draw3d(true); _lineNum = 0; return true; } else { + // Stop executing the script return cmdExit(params); } } @@ -871,81 +874,47 @@ bool Scripts::cmdAlterMap(ParamsIterator ¶ms) { return true; } -bool Scripts::cmdGiveExtended(ParamsIterator ¶ms) { +bool Scripts::cmdGiveMulti(ParamsIterator ¶ms) { Party &party = *_vm->_party; - int mode1, mode2, mode3; - uint32 val1, val2, val3; + int modes[3]; + uint32 vals[3]; _refreshIcons = true; - mode1 = params.readByte(); - switch (mode1) { - case 16: - case 34: - case 100: - val1 = params.readUint32LE(); - break; - case 25: - case 35: - case 101: - case 106: - val1 = params.readUint16LE(); - break; - default: - val1 = params.readByte(); - break; - } - - mode2 = params.readByte(); - switch (mode2) { - case 16: - case 34: - case 100: - val2 = params.readUint32LE(); - break; - case 25: - case 35: - case 101: - case 106: - val2 = params.readUint16LE(); - break; - default: - val2 = params.readByte(); - break; - } - - mode3 = params.readByte(); - switch (mode3) { - case 16: - case 34: - case 100: - val3 = params.readUint32LE(); - break; - case 25: - case 35: - case 101: - case 106: - val3 = params.readUint16LE(); - break; - default: - val3 = params.readByte(); - break; + for (int idx = 0; idx < 3; ++idx) { + modes[idx] = params.readByte(); + switch (modes[idx]) { + case 16: + case 34: + case 100: + vals[idx] = params.readUint32LE(); + break; + case 25: + case 35: + case 101: + case 106: + vals[idx] = params.readUint16LE(); + break; + default: + vals[idx] = params.readByte(); + break; + } } _scriptExecuted = true; - bool result = party.giveExt(mode1, val1, mode2, val2, mode3, val3, + bool result = party.giveExt(modes[0], vals[0], modes[1], vals[1], modes[2], vals[2], (_charIndex > 0) ? _charIndex - 1 : 0); if (result) { if (_animCounter == 255) { _animCounter = 0; return cmdExit(params); - } else if (mode1 == 67 || mode2 == 67 || mode3 == 67) { + } else if (modes[0] == 67 || modes[1] == 67 || modes[2] == 67) { _animCounter = 1; } else { return cmdExit(params); } } else { - if (mode1 == 67 || mode2 == 67 || mode3 == 67) + if (modes[0] == 67 || modes[1] == 67 || modes[2] == 67) return cmdExit(params); } @@ -1463,10 +1432,10 @@ void Scripts::doEnding(const Common::String &endStr) { int state = 0; for (uint idx = 0; idx < party._activeParty.size(); ++idx) { Character &player = party._activeParty[idx]; - if (player.hasAward(77)) { + if (player.hasAward(SUPER_GOOBER)) { state = 2; break; - } else if (player.hasAward(76)) { + } else if (player.hasAward(GOOBER)) { state = 1; break; } diff --git a/engines/xeen/scripts.h b/engines/xeen/scripts.h index 4c81185c54..9332018092 100644 --- a/engines/xeen/scripts.h +++ b/engines/xeen/scripts.h @@ -54,7 +54,7 @@ enum Opcode { OP_DoTownEvent = 0x11, OP_Exit = 0x12, OP_AfterMap = 0x13, - OP_GiveExtended = 0x14, + OP_GiveMulti = 0x14, OP_ConfirmWord = 0x15, OP_Damage = 0x16, OP_JumpRnd = 0x17, @@ -312,9 +312,9 @@ private: bool cmdAlterMap(ParamsIterator ¶ms); /** - * + * Gives up to three different item/amounts to various character and/or party properties */ - bool cmdGiveExtended(ParamsIterator ¶ms); + bool cmdGiveMulti(ParamsIterator ¶ms); /** * Prompts the user to enter a word for passwords or mirror diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 028f62101a..68e7a0ce14 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -3587,42 +3587,44 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; // These constants ensure a border of 2px on the left and of each rounded square - int xstart = (x1 > 2) ? x1 - 2 : x1; - int ystart = y1; - int width = w + offset + 2; - int height = h + offset + 1; - + Common::Rect shadowRect(w + offset + 2, h + offset + 1); + shadowRect.translate((x1 > 2) ? x1 - 2 : x1, y1); + + // The rounded rectangle drawn on top of this shadow is guaranteed + // to occlude entirely the following rect with a non-transparent color. + // As an optimization, we don't draw the shadow inside of it. + Common::Rect occludingRect(x1, y1, x1 + w, y1 + h); + occludingRect.top += r; + occludingRect.bottom -= r; + + // Soft shadows are constructed by drawing increasingly + // darker and smaller rectangles on top of each other. for (int i = offset; i >= 0; i--) { int f, ddF_x, ddF_y; int x, y, px, py; - PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); - PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); - PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r); - PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + height - r); - PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart); + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.top + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.top + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.bottom - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.bottom - r); - int short_h = height - (2 * r) + 2; PixelType color = _format.RGBToColor(0, 0, 0); BE_RESET(); - // HACK: As we are drawing circles exploting 8-axis symmetry, + // HACK: As we are drawing circles exploiting 8-axis symmetry, // there are 4 pixels on each circle which are drawn twice. // this is ok on filled circles, but when blending on surfaces, // we cannot let it blend twice. awful. uint32 hb = 0; + // Draw the top and bottom parts of the shadow. Those parts have rounded corners. while (x++ < y) { BE_ALGORITHM(); if (((1 << x) & hb) == 0) { blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha); - - // Will create a dark line of pixles if left out - if (hb > 0) { - blendFill(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha); - } + blendFill(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha); hb |= (1 << x); } @@ -3633,17 +3635,26 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { } } - ptr_fill += pitch * r; - while (short_h--) { - blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha); + // Draw the middle part of the shadow. This part is a rectangle with regular corners. + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(0, shadowRect.top + r); + for (int y2 = shadowRect.top + r; y2 < shadowRect.bottom - r + 1; y2++) { + + if (occludingRect.top <= y2 && y2 < occludingRect.bottom) { + if (shadowRect.left < occludingRect.left) { + blendFill(ptr_fill + shadowRect.left, ptr_fill + occludingRect.left, color, (uint8)alpha); + } + if (occludingRect.right < shadowRect.right + 1) { + blendFill(ptr_fill + occludingRect.right, ptr_fill + shadowRect.right + 1, color, (uint8)alpha); + } + } else { + blendFill(ptr_fill + shadowRect.left, ptr_fill + shadowRect.right + 1, color, (uint8)alpha); + } + ptr_fill += pitch; } - // Make shadow smaller each iteration, and move it one pixel inward - xstart += 1; - ystart += 1; - width -= 2; - height -= 2; + // Make shadow smaller each iteration + shadowRect.grow(-1); if (_shadowFillMode == kShadowExponential) // Multiply with expfactor @@ -3661,27 +3672,32 @@ drawRoundedSquareShadowClip(int x1, int y1, int r, int w, int h, int offset) { uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; // These constants ensure a border of 2px on the left and of each rounded square - int xstart = (x1 > 2) ? x1 - 2 : x1; - int ystart = y1; - int width = w + offset + 2; - int height = h + offset + 1; - + Common::Rect shadowRect(w + offset + 2, h + offset + 1); + shadowRect.translate((x1 > 2) ? x1 - 2 : x1, y1); + + // The rounded rectangle drawn on top of this shadow is guaranteed + // to occlude entirely the following rect with a non-transparent color. + // As an optimization, we don't draw the shadow inside of it. + Common::Rect occludingRect(x1, y1, x1 + w, y1 + h); + occludingRect.top += r; + occludingRect.bottom -= r; + + // Soft shadows are constructed by drawing increasingly + // darker and smaller rectangles on top of each other. for (int i = offset; i >= 0; i--) { int f, ddF_x, ddF_y; int x, y, px, py; - PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); - PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); - PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r); - PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + height - r); - PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart); + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.top + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.top + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.bottom - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.bottom - r); - int short_h = height - (2 * r) + 2; PixelType color = _format.RGBToColor(0, 0, 0); BE_RESET(); - // HACK: As we are drawing circles exploting 8-axis symmetry, + // HACK: As we are drawing circles exploiting 8-axis symmetry, // there are 4 pixels on each circle which are drawn twice. // this is ok on filled circles, but when blending on surfaces, // we cannot let it blend twice. awful. @@ -3692,36 +3708,46 @@ drawRoundedSquareShadowClip(int x1, int y1, int r, int w, int h, int offset) { if (((1 << x) & hb) == 0) { blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha, - xstart + r - y, ystart + r - x); + shadowRect.left + r - y, shadowRect.top + r - x); + blendFillClip(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha, + shadowRect.left + r - y, shadowRect.bottom - r + x); - // Will create a dark line of pixles if left out - if (hb > 0) { - blendFillClip(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha, - xstart + r - y, ystart + height - r + x); - } hb |= (1 << x); } if (((1 << y) & hb) == 0) { - blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, xstart + r - x, ystart + r - y); - blendFillClip(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha, xstart + r - x, ystart + height - r + y); + blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, + shadowRect.left + r - x, shadowRect.top + r - y); + blendFillClip(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha, + shadowRect.left + r - x, shadowRect.bottom - r + y); + hb |= (1 << y); } } - ptr_fill += pitch * r; - int orig_short_h = short_h; - while (short_h--) { - blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha, - xstart, ystart + r + orig_short_h - short_h - 1); + // Draw the middle part of the shadow. This part is a rectangle with regular corners. + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(0, shadowRect.top + r); + for (int y2 = shadowRect.top + r; y2 < shadowRect.bottom - r + 1; y2++) { + + if (occludingRect.top <= y2 && y2 < occludingRect.bottom) { + if (shadowRect.left < occludingRect.left) { + blendFillClip(ptr_fill + shadowRect.left, ptr_fill + occludingRect.left, color, (uint8)alpha, + shadowRect.left, y2); + } + if (occludingRect.right < shadowRect.right + 1) { + blendFillClip(ptr_fill + occludingRect.right, ptr_fill + shadowRect.right + 1, color, (uint8)alpha, + occludingRect.right, y2); + } + } else { + blendFillClip(ptr_fill + shadowRect.left, ptr_fill + shadowRect.right + 1, color, (uint8)alpha, + shadowRect.left, y2); + } + ptr_fill += pitch; } - // Make shadow smaller each iteration, and move it one pixel inward - xstart += 1; - ystart += 1; - width -= 2; - height -= 2; + // Make shadow smaller each iteration + shadowRect.grow(-1); if (_shadowFillMode == kShadowExponential) // Multiply with expfactor diff --git a/gui/about.cpp b/gui/about.cpp index 25912557f9..a72a4ed09b 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -57,7 +57,7 @@ enum { static const char *copyright_text[] = { "", -"C0""Copyright (C) 2001-2017 The ScummVM Team", +"C0""Copyright (C) 2001-2018 The ScummVM Team", "C0""http://www.scummvm.org", "", "C0""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 binary.", |