1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-05 00:49:09 +02:00

Locks for combination artifacts largely implemented, only one or two bugs when moving them around in a certain way. Artifact assembly still remaining.

To make sure these artifacts get (un)equipped properly the functions CArtHandler::equipArtifact and CArtHandler::unequipArtifact should be used instead of modifying artifWorn manually.
This commit is contained in:
OnionKnight
2010-02-08 21:17:22 +00:00
parent 28f8ef3b0f
commit 790a77c280
12 changed files with 248 additions and 72 deletions

View File

@ -257,7 +257,9 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
sprintf(bufor, CGI->generaltexth->allTexts[205].c_str(), hero->name.c_str(), hero->mana, hero->manaLimit()); sprintf(bufor, CGI->generaltexth->allTexts[205].c_str(), hero->name.c_str(), hero->mana, hero->manaLimit());
spellPointsArea->text = std::string(bufor); spellPointsArea->text = std::string(bufor);
artifs->updateState = true;
artifs->setHero(hero); artifs->setHero(hero);
artifs->updateState = false;
//if we have exchange window with this hero open //if we have exchange window with this hero open
bool noDismiss=false; bool noDismiss=false;

View File

@ -853,7 +853,9 @@ void CPlayerInterface::heroArtifactSetChanged(const CGHeroInstance*hero)
{ {
if(cew->heroInst[g] == hero) if(cew->heroInst[g] == hero)
{ {
cew->artifs[g]->updateState = true;
cew->artifs[g]->setHero(hero); cew->artifs[g]->setHero(hero);
cew->artifs[g]->updateState = false;
} }
} }
cew->prepareBackground(); cew->prepareBackground();

View File

@ -3657,9 +3657,20 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
ourOwner->commonInfo->destSlotID = slotID; ourOwner->commonInfo->destSlotID = slotID;
ourOwner->commonInfo->destArtifact = ourArt; ourOwner->commonInfo->destArtifact = ourArt;
// Special case when the dest artifact can't be fit into the src slot.
CGHeroInstance *destHero = const_cast<CGHeroInstance *>(ourOwner->curHero);
CGI->arth->unequipArtifact(destHero->artifWorn, slotID);
const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->srcAOH;
ui16 srcSlotID = ourOwner->commonInfo->srcSlotID;
if (ourArt && srcSlotID < 19 && !ourArt->fitsAt(srcAOH->curHero->artifWorn, srcSlotID)) {
// Put dest artifact into owner's backpack.
ourOwner->commonInfo->srcAOH = ourOwner;
ourOwner->commonInfo->srcSlotID = ourOwner->curHero->artifacts.size() + 19;
}
LOCPLINT->cb->swapArtifacts( LOCPLINT->cb->swapArtifacts(
ourOwner->commonInfo->srcAOH->curHero, srcAOH->curHero,
ourOwner->commonInfo->srcSlotID, srcSlotID,
ourOwner->curHero, ourOwner->curHero,
slotID); slotID);
} }
@ -3676,7 +3687,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
void CArtPlace::clickRight(tribool down, bool previousState) void CArtPlace::clickRight(tribool down, bool previousState)
{ {
if(text.size()) //if there is no description, do nothing ;] if(!locked() && text.size()) //if there is no description or it's a lock, do nothing ;]
LRClickableAreaWTextComp::clickRight(down, previousState); LRClickableAreaWTextComp::clickRight(down, previousState);
} }
@ -3685,8 +3696,10 @@ void CArtPlace::clickRight(tribool down, bool previousState)
*/ */
void CArtPlace::select () void CArtPlace::select ()
{ {
if (locked())
return;
CGI->curh->dragAndDropCursor(graphics->artDefs->ourImages[ourArt->id].bitmap); CGI->curh->dragAndDropCursor(graphics->artDefs->ourImages[ourArt->id].bitmap);
ourOwner->markPossibleSlots(ourArt);
ourOwner->commonInfo->srcArtifact = ourArt; ourOwner->commonInfo->srcArtifact = ourArt;
ourOwner->commonInfo->srcSlotID = slotID; ourOwner->commonInfo->srcSlotID = slotID;
@ -3695,9 +3708,10 @@ void CArtPlace::select ()
// Temporarily remove artifact from hero. // Temporarily remove artifact from hero.
CGHeroInstance* hero = const_cast<CGHeroInstance*>(ourOwner->curHero); CGHeroInstance* hero = const_cast<CGHeroInstance*>(ourOwner->curHero);
if (slotID < 19) if (slotID < 19)
hero->artifWorn.erase(slotID); CGI->arth->unequipArtifact(hero->artifWorn, slotID);
else else
hero->artifacts.erase(hero->artifacts.begin() + (slotID - 19)); hero->artifacts.erase(hero->artifacts.begin() + (slotID - 19));
ourOwner->markPossibleSlots(ourArt);
hero->recreateArtBonuses(); hero->recreateArtBonuses();
// Update the hero bonuses. // Update the hero bonuses.
@ -3776,14 +3790,10 @@ bool CArtPlace::fitsHere(const CArtifact * art)
return true; return true;
// Anything can but War Machines can be placed in backpack. // Anything can but War Machines can be placed in backpack.
if (slotID >= 19) { if (slotID >= 19)
return !CGI->arth->isBigArtifact(art->id); return !CGI->arth->isBigArtifact(art->id);
} else if (vstd::contains(art->possibleSlots, slotID)) {
// TODO: Deal with combinational at dest and as src.
return true;
}
return false; return art->fitsAt(ourOwner->curHero->artifWorn, slotID);
} }
CArtPlace::~CArtPlace() CArtPlace::~CArtPlace()
@ -3988,21 +3998,20 @@ void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
backpackPos++; backpackPos++;
} }
if (commonInfo->srcAOH == this) { if (updateState && commonInfo->srcAOH == this) {
curHero = hero;
// A swap was made, make the replaced artifact the current selected. // A swap was made, make the replaced artifact the current selected.
if (commonInfo->destSlotID < 19 && commonInfo->destArtifact) { if (commonInfo->destSlotID < 19 && commonInfo->destArtifact) {
// Temporarily remove artifact from hero. // Temporarily remove artifact from hero.
CGHeroInstance * hero = const_cast<CGHeroInstance *>(curHero); CGHeroInstance * nonconstCurHero = const_cast<CGHeroInstance *>(curHero);
if (commonInfo->srcSlotID < 19) if (commonInfo->srcSlotID < 19)
hero->artifWorn.erase(commonInfo->srcSlotID); CGI->arth->unequipArtifact(nonconstCurHero->artifWorn, commonInfo->srcSlotID);
else else
hero->artifacts.erase(hero->artifacts.begin() + (commonInfo->srcSlotID - 19)); nonconstCurHero->artifacts.erase(nonconstCurHero->artifacts.begin() + (commonInfo->srcSlotID - 19));
hero->recreateArtBonuses(); nonconstCurHero->recreateArtBonuses();
// Source <- Dest // Source <- Dest
//commonInfo->srcAOH = commonInfo->destAOH;
commonInfo->srcArtifact = commonInfo->destArtifact; commonInfo->srcArtifact = commonInfo->destArtifact;
//commonInfo->srcSlotID = commonInfo->destSlotID;
// Reset destination parameters. // Reset destination parameters.
commonInfo->destAOH = NULL; commonInfo->destAOH = NULL;
@ -4059,7 +4068,7 @@ void CArtifactsOfHero::rollback()
if (commonInfo->srcSlotID != -1) { if (commonInfo->srcSlotID != -1) {
// Put a held artifact back to it's spot. // Put a held artifact back to it's spot.
if (commonInfo->srcSlotID < 19) if (commonInfo->srcSlotID < 19)
hero->artifWorn[commonInfo->srcSlotID] = commonInfo->srcArtifact->id; CGI->arth->equipArtifact(hero->artifWorn, commonInfo->srcSlotID, commonInfo->srcArtifact->id);
else else
hero->artifacts.insert(hero->artifacts.begin() + (commonInfo->srcSlotID - 19), commonInfo->srcArtifact->id); hero->artifacts.insert(hero->artifacts.begin() + (commonInfo->srcSlotID - 19), commonInfo->srcArtifact->id);
} else { // Held swapped artifact. } else { // Held swapped artifact.
@ -4069,7 +4078,7 @@ void CArtifactsOfHero::rollback()
if (artWorn[i]->fitsHere(commonInfo->srcArtifact) if (artWorn[i]->fitsHere(commonInfo->srcArtifact)
&& curHero->artifWorn.find(i) == curHero->artifWorn.end()) && curHero->artifWorn.find(i) == curHero->artifWorn.end())
{ {
hero->artifWorn[i] = commonInfo->srcArtifact->id; CGI->arth->equipArtifact(hero->artifWorn, i, commonInfo->srcArtifact->id);
break; break;
} }
} }
@ -4137,6 +4146,8 @@ void CArtifactsOfHero::markPossibleSlots (const CArtifact* art)
for (int i = 0; i < (*it)->artWorn.size(); i++) { for (int i = 0; i < (*it)->artWorn.size(); i++) {
if ((*it)->artWorn[i]->fitsHere(art)) if ((*it)->artWorn[i]->fitsHere(art))
(*it)->artWorn[i]->marked = true; (*it)->artWorn[i]->marked = true;
else
(*it)->artWorn[i]->marked = false;
} }
} }
} }
@ -4166,6 +4177,9 @@ void CArtifactsOfHero::setSlotData (CArtPlace* artPlace, int slotID)
if (artPlace->ourArt) { if (artPlace->ourArt) {
artPlace->text = artPlace->ourArt->Description(); artPlace->text = artPlace->ourArt->Description();
if (artPlace->locked()) // Locks should appear as empty.
artPlace->hoverText = CGI->generaltexth->allTexts[507];
else
artPlace->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1].c_str()) % artPlace->ourArt->Name().c_str()); artPlace->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1].c_str()) % artPlace->ourArt->Name().c_str());
} else { } else {
eraseSlotData(artPlace, slotID); eraseSlotData(artPlace, slotID);
@ -4184,7 +4198,7 @@ void CArtifactsOfHero::eraseSlotData (CArtPlace* artPlace, int slotID)
} }
CArtifactsOfHero::CArtifactsOfHero(const SDL_Rect & position) : CArtifactsOfHero::CArtifactsOfHero(const SDL_Rect & position) :
backpackPos(0) backpackPos(0), updateState(false)
{ {
pos = position; pos = position;
artWorn.resize(19); artWorn.resize(19);

View File

@ -2,6 +2,7 @@
#define __GUICLASSES_H__ #define __GUICLASSES_H__
#include "../global.h" #include "../global.h"
#include "../hch/CArtHandler.h"
#include "SDL_framerate.h" #include "SDL_framerate.h"
#include "GUIBase.h" #include "GUIBase.h"
#include "FunctionList.h" #include "FunctionList.h"
@ -691,10 +692,15 @@ public:
void activate(); void activate();
void deactivate(); void deactivate();
void show(SDL_Surface * to); void show(SDL_Surface * to);
bool fitsHere(const CArtifact * art); //returns true if given artifact can be placed here bool fitsHere (const CArtifact * art); //returns true if given artifact can be placed here
bool locked () const;
~CArtPlace(); //d-tor ~CArtPlace(); //d-tor
}; };
inline bool CArtPlace::locked () const
{
return ourArt && ourArt->id == 145;
}
class CArtifactsOfHero : public CIntObject class CArtifactsOfHero : public CIntObject
{ {
@ -702,7 +708,7 @@ class CArtifactsOfHero : public CIntObject
std::vector<CArtPlace *> artWorn; // 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5 std::vector<CArtPlace *> artWorn; // 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
std::vector<CArtPlace *> backpack; //hero's visible backpack (only 5 elements!) std::vector<CArtPlace *> backpack; //hero's visible backpack (only 5 elements!)
int backpackPos; //unmber of first art visible in backpack (in hero's vector) int backpackPos; //number of first art visible in backpack (in hero's vector)
public: public:
struct SCommonPart struct SCommonPart
@ -716,6 +722,8 @@ public:
const CArtifact * destArtifact; // For swapping. const CArtifact * destArtifact; // For swapping.
} * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally } * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally
bool updateState; // Whether the commonInfo should be updated on setHero or not.
AdventureMapButton * leftArtRoll, * rightArtRoll; AdventureMapButton * leftArtRoll, * rightArtRoll;
void activate(); void activate();

View File

@ -6,6 +6,7 @@
#include <boost/assign/std/vector.hpp> #include <boost/assign/std/vector.hpp>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
#include "../lib/VCMI_Lib.h" #include "../lib/VCMI_Lib.h"
extern CLodHandler *bitmaph; extern CLodHandler *bitmaph;
using namespace boost::assign; using namespace boost::assign;
@ -36,11 +37,69 @@ const std::string & CArtifact::Description() const
return VLC->generaltexth->artifDescriptions[id]; return VLC->generaltexth->artifDescriptions[id];
} }
bool CArtifact::isBig () const inline bool CArtifact::isBig () const
{ {
return VLC->arth->isBigArtifact(id); return VLC->arth->isBigArtifact(id);
} }
/**
* Checks whether the artifact fits at a given slot.
* @param artifWorn A hero's set of worn artifacts.
*/
bool CArtifact::fitsAt (const std::map<ui16, ui32> &artifWorn, ui16 slotID) const
{
if (!vstd::contains(possibleSlots, slotID))
return false;
// Can't put an artifact in a locked slot.
std::map<ui16, ui32>::const_iterator it = artifWorn.find(slotID);
if (it != artifWorn.end() && it->second == 145)
return false;
// Check if a combination artifact fits.
// TODO: Might want a more general algorithm?
// Assumes that misc & rings fits only in their slots, and others in only one slot and no duplicates.
if (constituents != NULL) {
std::map<ui16, ui32> tempArtifWorn = artifWorn;
const ui16 ringSlots[] = {6, 7};
const ui16 miscSlots[] = {9, 10, 11, 12, 18};
int rings = 0;
int misc = 0;
VLC->arth->unequipArtifact(tempArtifWorn, slotID);
BOOST_FOREACH(ui32 constituentID, *constituents) {
const CArtifact& constituent = VLC->arth->artifacts[constituentID];
const int slot = constituent.possibleSlots[0];
if (slot == 6 || slot == 7)
rings++;
else if (slot >= 9 && slot <= 12 || slot == 18)
misc++;
else if (tempArtifWorn.find(slot) != tempArtifWorn.end())
return false;
}
// Ensure enough ring slots are free
for (int i = 0; i < sizeof(ringSlots)/sizeof(*ringSlots); i++) {
if (tempArtifWorn.find(ringSlots[i]) == tempArtifWorn.end() || ringSlots[i] == slotID)
rings--;
}
if (rings > 0)
return false;
// Ensure enough misc slots are free.
for (int i = 0; i < sizeof(miscSlots)/sizeof(*miscSlots); i++) {
if (tempArtifWorn.find(miscSlots[i]) == tempArtifWorn.end() || miscSlots[i] == slotID)
misc--;
}
if (misc > 0)
return false;
}
return true;
}
CArtHandler::CArtHandler() CArtHandler::CArtHandler()
{ {
VLC->arth = this; VLC->arth = this;
@ -52,7 +111,7 @@ CArtHandler::CArtHandler()
void CArtHandler::loadArtifacts(bool onlyTxt) void CArtHandler::loadArtifacts(bool onlyTxt)
{ {
std::vector<ui16> slots; std::vector<ui16> slots;
slots += 17, 16, 15,14,13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0; slots += 17, 16, 15, 14, 13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0;
static std::map<char, CArtifact::EartClass> classes = static std::map<char, CArtifact::EartClass> classes =
map_list_of('S',CArtifact::ART_SPECIAL)('T',CArtifact::ART_TREASURE)('N',CArtifact::ART_MINOR)('J',CArtifact::ART_MAJOR)('R',CArtifact::ART_RELIC); map_list_of('S',CArtifact::ART_SPECIAL)('T',CArtifact::ART_TREASURE)('N',CArtifact::ART_MINOR)('J',CArtifact::ART_MAJOR)('R',CArtifact::ART_RELIC);
std::string buf = bitmaph->getTextFile("ARTRAITS.TXT"), dump, pom; std::string buf = bitmaph->getTextFile("ARTRAITS.TXT"), dump, pom;
@ -85,65 +144,65 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
if(desc[0] == '\"' && desc[desc.size()-1] == '\"') if(desc[0] == '\"' && desc[desc.size()-1] == '\"')
desc = desc.substr(1,desc.size()-2); desc = desc.substr(1,desc.size()-2);
// Fill in information about combined artifacts. // Fill in information about combined artifacts. Should perhaps be moved to a config file?
switch (nart.id) { switch (nart.id) {
case 129: // Angelic Alliance case 129: // Angelic Alliance
nart.constituents = new std::vector<ui32>(6); nart.constituents = new std::vector<ui32>();
*nart.constituents += 31, 32, 33, 34, 35, 36; *nart.constituents += 31, 32, 33, 34, 35, 36;
break; break;
case 130: // Cloak of the Undead King case 130: // Cloak of the Undead King
nart.constituents = new std::vector<ui32>(3); nart.constituents = new std::vector<ui32>();
*nart.constituents += 54, 55, 56; *nart.constituents += 54, 55, 56;
break; break;
case 131: // Elixir of Life case 131: // Elixir of Life
nart.constituents = new std::vector<ui32>(3); nart.constituents = new std::vector<ui32>();
*nart.constituents += 94, 95, 96; *nart.constituents += 94, 95, 96;
break; break;
case 132: // Armor of the Damned case 132: // Armor of the Damned
nart.constituents = new std::vector<ui32>(4); nart.constituents = new std::vector<ui32>();
*nart.constituents += 8, 14, 20, 26; *nart.constituents += 8, 14, 20, 26;
break; break;
case 133: // Statue of Legion case 133: // Statue of Legion
nart.constituents = new std::vector<ui32>(5); nart.constituents = new std::vector<ui32>();
*nart.constituents += 118, 119, 120, 121, 122; *nart.constituents += 118, 119, 120, 121, 122;
break; break;
case 134: // Power of the Dragon Father case 134: // Power of the Dragon Father
nart.constituents = new std::vector<ui32>(9); nart.constituents = new std::vector<ui32>();
*nart.constituents += 37, 38, 39, 40, 41, 42, 43, 44, 45; *nart.constituents += 37, 38, 39, 40, 41, 42, 43, 44, 45;
break; break;
case 135: // Titan's Thunder case 135: // Titan's Thunder
nart.constituents = new std::vector<ui32>(4); nart.constituents = new std::vector<ui32>();
*nart.constituents += 12, 18, 24, 30; *nart.constituents += 12, 18, 24, 30;
break; break;
case 136: // Admiral's Hat case 136: // Admiral's Hat
nart.constituents = new std::vector<ui32>(2); nart.constituents = new std::vector<ui32>();
*nart.constituents += 71, 123; *nart.constituents += 71, 123;
break; break;
case 137: // Bow of the Sharpshooter case 137: // Bow of the Sharpshooter
nart.constituents = new std::vector<ui32>(3); nart.constituents = new std::vector<ui32>();
*nart.constituents += 60, 61, 62; *nart.constituents += 60, 61, 62;
break; break;
case 138: // Wizards' Well case 138: // Wizards' Well
nart.constituents = new std::vector<ui32>(3); nart.constituents = new std::vector<ui32>();
*nart.constituents += 73, 74, 75; *nart.constituents += 73, 74, 75;
break; break;
case 139: // Ring of the Magi case 139: // Ring of the Magi
nart.constituents = new std::vector<ui32>(3); nart.constituents = new std::vector<ui32>();
*nart.constituents += 76, 77, 78; *nart.constituents += 76, 77, 78;
break; break;
case 140: // Cornucopia case 140: // Cornucopia
nart.constituents = new std::vector<ui32>(4); nart.constituents = new std::vector<ui32>();
*nart.constituents += 109, 110, 111, 113; *nart.constituents += 109, 110, 111, 113;
break; break;
@ -485,3 +544,75 @@ void CArtHandler::clear()
majors.clear(); majors.clear();
relics.clear(); relics.clear();
} }
/**
* Locally equips an artifact to a hero's worn slots. Unequips an already present artifact.
* Does not test if the operation is legal.
* @param artifWorn A hero's set of worn artifacts.
*/
void CArtHandler::equipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID, ui32 artifactID)
{
unequipArtifact(artifWorn, slotID);
const CArtifact &artifact = artifacts[artifactID];
// Add artifact.
artifWorn[slotID] = artifactID;
// Add locks, in reverse order of being removed.
if (artifact.constituents != NULL) {
bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
BOOST_FOREACH(ui32 constituentID, *artifact.constituents) {
const CArtifact &constituent = artifacts[constituentID];
if (!destConsumed && vstd::contains(constituent.possibleSlots, slotID)) {
destConsumed = true;
} else {
BOOST_FOREACH(ui16 slot, constituent.possibleSlots) {
if (artifWorn.find(slot) == artifWorn.end()) {
artifWorn[slot] = 145;
break;
}
}
}
}
}
}
/**
* Locally unequips an artifact from a hero's worn slots.
* Does not test if the operation is legal.
* @param artifWorn A hero's set of worn artifacts.
*/
void CArtHandler::unequipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID)
{
if (artifWorn.find(slotID) == artifWorn.end())
return;
const CArtifact &artifact = artifacts[artifWorn[slotID]];
// Remove artifact, if it's not already removed.
artifWorn.erase(slotID);
// Remove locks, in reverse order of being added.
if (artifact.constituents != NULL) {
bool destConsumed = false;
BOOST_FOREACH(ui32 constituentID, *artifact.constituents) {
const CArtifact &constituent = artifacts[constituentID];
if (!destConsumed && vstd::contains(constituent.possibleSlots, slotID)) {
destConsumed = true;
} else {
BOOST_REVERSE_FOREACH(ui16 slot, constituent.possibleSlots) {
if (artifWorn.find(slot) != artifWorn.end() && artifWorn[slot] == 145) {
artifWorn.erase(slot);
break;
}
}
}
}
}
}

View File

@ -26,6 +26,7 @@ public:
const std::string &Name() const; //getter const std::string &Name() const; //getter
const std::string &Description() const; //getter const std::string &Description() const; //getter
bool isBig () const; bool isBig () const;
bool fitsAt (const std::map<ui16, ui32> &artifWorn, ui16 slot) const;
ui32 price; ui32 price;
std::vector<ui16> possibleSlots; //ids of slots where artifact can be placed std::vector<ui16> possibleSlots; //ids of slots where artifact can be placed
@ -53,6 +54,8 @@ public:
void addBonuses(); void addBonuses();
void clear(); void clear();
bool isBigArtifact (ui32 artID) {return bigArtifacts.find(artID) != bigArtifacts.end();} bool isBigArtifact (ui32 artID) {return bigArtifacts.find(artID) != bigArtifacts.end();}
void equipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID, ui32 artifactID);
void unequipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID);
static int convertMachineID(int id, bool creToArt); static int convertMachineID(int id, bool creToArt);
CArtHandler(); CArtHandler();

View File

@ -704,9 +704,9 @@ void CGHeroInstance::initHero()
if(!vstd::contains(artifWorn, 16) && type->startingSpell >= 0) //no catapult means we haven't read pre-existant set if(!vstd::contains(artifWorn, 16) && type->startingSpell >= 0) //no catapult means we haven't read pre-existant set
{ {
artifWorn[17] = 0; //give spellbook VLC->arth->equipArtifact(artifWorn, 17, 0); //give spellbook
} }
artifWorn[16] = 3; //everyone has a catapult VLC->arth->equipArtifact(artifWorn, 16, 3); //everyone has a catapult
if(portrait < 0 || portrait == 255) if(portrait < 0 || portrait == 255)
portrait = subID; portrait = subID;
@ -754,10 +754,10 @@ void CGHeroInstance::initHero()
switch (pom) switch (pom)
{ {
case 145: //catapult case 145: //catapult
artifWorn[16] = 3; VLC->arth->equipArtifact(artifWorn, 16, 3);
break; break;
default: default:
artifWorn[9+CArtHandler::convertMachineID(pom,true)] = CArtHandler::convertMachineID(pom,true); VLC->arth->equipArtifact(artifWorn, 9+CArtHandler::convertMachineID(pom,true), CArtHandler::convertMachineID(pom,true));
break; break;
} }
continue; continue;
@ -1220,7 +1220,7 @@ void CGHeroInstance::giveArtifact (ui32 aid)
if (artifact.isBig()) { if (artifact.isBig()) {
for (std::vector<ui16>::const_iterator it = artifact.possibleSlots.begin(); it != artifact.possibleSlots.end(); ++it) { for (std::vector<ui16>::const_iterator it = artifact.possibleSlots.begin(); it != artifact.possibleSlots.end(); ++it) {
if (artifWorn.find(*it) == artifWorn.end()) { if (artifWorn.find(*it) == artifWorn.end()) {
artifWorn[*it] = aid; VLC->arth->equipArtifact(artifWorn, *it, aid);
break; break;
} }
} }

View File

@ -1490,7 +1490,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
std::vector<ui16>::iterator slot = vstd::findFirstNot(hero->artifWorn,toGive->possibleSlots); std::vector<ui16>::iterator slot = vstd::findFirstNot(hero->artifWorn,toGive->possibleSlots);
if(slot!=toGive->possibleSlots.end()) if(slot!=toGive->possibleSlots.end())
{ {
hero->artifWorn[*slot] = toGive->id; VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive->id);
hero->recreateArtBonuses(); hero->recreateArtBonuses();
} }
else else

View File

@ -31,7 +31,7 @@ struct DLL_EXPORT HeroBonus
NONEVIL_ALIGNMENT_MIX, //good and neutral creatures can be mixed without morale penalty NONEVIL_ALIGNMENT_MIX, //good and neutral creatures can be mixed without morale penalty
HP_REGENERATION, //regenerates a certain amount of hp for the top of each stack every turn, val - hp regained HP_REGENERATION, //regenerates a certain amount of hp for the top of each stack every turn, val - hp regained
LEVEL_SPELL_IMMUNITY, //val - spell level creatures become immune to and below LEVEL_SPELL_IMMUNITY, //val - spell level creatures become immune to and below
//not handled yet: //might not be handled yet:
MAGIC_RESISTANCE, // % MAGIC_RESISTANCE, // %
SECONDARY_SKILL_PREMY, //% SECONDARY_SKILL_PREMY, //%
SURRENDER_DISCOUNT, //% SURRENDER_DISCOUNT, //%

View File

@ -464,14 +464,14 @@ DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, int art)
if(art<0) if(art<0)
{ {
if(pos<19) if(pos<19)
artifWorn.erase(pos); VLC->arth->unequipArtifact(artifWorn, pos);
else else
artifacts.erase(artifacts.begin() + (pos - 19)); artifacts.erase(artifacts.begin() + (pos - 19));
} }
else else
{ {
if (pos < 19) { if (pos < 19) {
artifWorn[pos] = art; VLC->arth->equipArtifact(artifWorn, pos, (ui32) art);
} else { // Goes into the backpack. } else { // Goes into the backpack.
if(pos - 19 < artifacts.size()) if(pos - 19 < artifacts.size())
artifacts.insert(artifacts.begin() + (pos - 19), art); artifacts.insert(artifacts.begin() + (pos - 19), art);

View File

@ -964,27 +964,27 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int
{ {
int id = readNormalNr(bufor,i, artidlen); i+=artidlen; int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
if(id!=artmask) if(id!=artmask)
nhi->artifWorn[pom] = id; VLC->arth->equipArtifact(nhi->artifWorn, pom, id);
} }
//misc5 art //17 //misc5 art //17
if(version>=SoD) if(version>=SoD)
{ {
int id = readNormalNr(bufor,i, artidlen); i+=artidlen; int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
if(id!=artmask) if(id!=artmask)
nhi->artifWorn[16] = id; VLC->arth->equipArtifact(nhi->artifWorn, 16, id);
else else
nhi->artifWorn[16] = 3; //catapult by default VLC->arth->equipArtifact(nhi->artifWorn, 16, 3); //catapult by default
} }
//spellbook //spellbook
int id = readNormalNr(bufor,i, artidlen); i+=artidlen; int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
if(id!=artmask) if(id!=artmask)
nhi->artifWorn[17] = id; VLC->arth->equipArtifact(nhi->artifWorn, 17, id);
//19 //???what is that? gap in file or what? - it's probably fifth slot.. //19 //???what is that? gap in file or what? - it's probably fifth slot..
if(version>RoE) if(version>RoE)
{ {
id = readNormalNr(bufor,i, artidlen); i+=artidlen; id = readNormalNr(bufor,i, artidlen); i+=artidlen;
if(id!=artmask) if(id!=artmask)
nhi->artifWorn[18] = id; VLC->arth->equipArtifact(nhi->artifWorn, 18, id);
} }
else else
i+=1; i+=1;
@ -1204,7 +1204,7 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i)
{ {
int id = readNormalNr(bufor,i, artidlen); i+=artidlen; int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
if(id!=artmask) if(id!=artmask)
cgh->artifWorn[pom] = id; VLC->arth->equipArtifact(cgh->artifWorn, pom, id);
} }
//misc5 art //17 //misc5 art //17
if(version>=SoD) if(version>=SoD)
@ -1217,13 +1217,13 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i)
//spellbook //spellbook
int id = readNormalNr(bufor,i, artidlen); i+=artidlen; int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
if(id!=artmask) if(id!=artmask)
cgh->artifWorn[17] = id; VLC->arth->equipArtifact(cgh->artifWorn, 17, id);
//19 //???what is that? gap in file or what? - it's probably fifth slot.. //19 //???what is that? gap in file or what? - it's probably fifth slot..
if(version>RoE) if(version>RoE)
{ {
id = readNormalNr(bufor,i, artidlen); i+=artidlen; id = readNormalNr(bufor,i, artidlen); i+=artidlen;
if(id!=artmask) if(id!=artmask)
cgh->artifWorn[18] = id; VLC->arth->equipArtifact(cgh->artifWorn, 18, id);
} }
else else
i+=1; i+=1;

View File

@ -1806,7 +1806,7 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
if( !vstd::contains(sha.artifWorn,art.possibleSlots[i]) ) if( !vstd::contains(sha.artifWorn,art.possibleSlots[i]) )
{ {
//we've found a free suitable slot //we've found a free suitable slot
sha.artifWorn[art.possibleSlots[i]] = artid; VLC->arth->equipArtifact(sha.artifWorn, art.possibleSlots[i], artid);
break; break;
} }
} }
@ -1822,7 +1822,7 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
{ {
if(!vstd::contains(sha.artifWorn,ui16(position))) if(!vstd::contains(sha.artifWorn,ui16(position)))
{ {
sha.artifWorn[position] = artid; VLC->arth->equipArtifact(sha.artifWorn, position, artid);
} }
else if (!art.isBig()) else if (!art.isBig())
{ {
@ -1850,7 +1850,7 @@ void CGameHandler::removeArtifact(int artid, int hid)
{ {
if (itr->second == artid) if (itr->second == artid)
{ {
sha.artifWorn.erase(itr); VLC->arth->unequipArtifact(sha.artifWorn, itr->first);
break; break;
} }
} }
@ -2536,6 +2536,7 @@ bool CGameHandler::garrisonSwap( si32 tid )
} }
} }
// With the amount of changes done to the function, it's more like transferArtifacts.
bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot) bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot)
{ {
CGHeroInstance *srcHero = gs->getHero(srcHeroID); CGHeroInstance *srcHero = gs->getHero(srcHeroID);
@ -2548,16 +2549,32 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot,
const CArtifact *srcArtifact = srcHero->getArt(srcSlot); const CArtifact *srcArtifact = srcHero->getArt(srcSlot);
const CArtifact *destArtifact = destHero->getArt(destSlot); const CArtifact *destArtifact = destHero->getArt(destSlot);
SetHeroArtifacts sha;
sha.hid = srcHeroID;
sha.artifacts = srcHero->artifacts;
sha.artifWorn = srcHero->artifWorn;
// Combinational artifacts needs to be removed first so they don't get denied movement because of their own locks.
if (srcHeroID == destHeroID && srcSlot < 19) {
VLC->arth->unequipArtifact(sha.artifWorn, srcSlot);
if (sha.artifWorn.find(destSlot) == sha.artifWorn.end())
destArtifact = NULL;
}
// Check if src/dest slots are appropriate for the artifacts exchanged. // Check if src/dest slots are appropriate for the artifacts exchanged.
// Moving to the backpack is always allowed. // Moving to the backpack is always allowed.
if ((!srcArtifact || destSlot < 19) if ((!srcArtifact || destSlot < 19)
&& (((srcArtifact && !vstd::contains(srcArtifact->possibleSlots, destSlot)) && (srcArtifact && !srcArtifact->fitsAt(srcHeroID == destHeroID ? sha.artifWorn : destHero->artifWorn, destSlot)))
|| (destArtifact && srcSlot < 19 && !vstd::contains(destArtifact->possibleSlots, srcSlot)))))
{ {
complain("Cannot swap artifacts!"); complain("Cannot swap artifacts!");
return false; return false;
} }
if ((srcArtifact && srcArtifact->id == 145) || (destArtifact && destArtifact->id == 145)) {
complain("Cannot move artifact locks.");
return false;
}
if (destSlot >= 19 && srcArtifact->isBig()) { if (destSlot >= 19 && srcArtifact->isBig()) {
complain("Cannot put big artifacts in backpack!"); complain("Cannot put big artifacts in backpack!");
return false; return false;
@ -2568,14 +2585,11 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot,
return false; return false;
} }
// Perform the exchange. // If dest does not fit in src, put it in dest's backpack instead.
SetHeroArtifacts sha; bool destFits = !destArtifact || srcSlot >= 19 || destArtifact->fitsAt(sha.artifWorn, srcSlot);
sha.hid = srcHeroID;
sha.artifacts = srcHero->artifacts;
sha.artifWorn = srcHero->artifWorn;
sha.setArtAtPos(srcSlot, -1); sha.setArtAtPos(srcSlot, -1);
if (destSlot < 19 && (destArtifact || srcSlot < 19)) if (destSlot < 19 && (destArtifact || srcSlot < 19) && destFits)
sha.setArtAtPos(srcSlot, destHero->getArtAtPos(destSlot)); sha.setArtAtPos(srcSlot, destHero->getArtAtPos(destSlot));
// Internal hero artifact arrangement. // Internal hero artifact arrangement.
@ -2593,6 +2607,8 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot,
sha.artifacts = destHero->artifacts; sha.artifacts = destHero->artifacts;
sha.artifWorn = destHero->artifWorn; sha.artifWorn = destHero->artifWorn;
sha.setArtAtPos(destSlot, srcArtifact ? srcArtifact->id : -1); sha.setArtAtPos(destSlot, srcArtifact ? srcArtifact->id : -1);
if (!destFits)
sha.setArtAtPos(sha.artifacts.size() + 19, destHero->getArtAtPos(destSlot));
sendAndApply(&sha); sendAndApply(&sha);
} }
@ -3026,7 +3042,7 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
sha.hid = h->id; sha.hid = h->id;
sha.artifacts = h->artifacts; sha.artifacts = h->artifacts;
sha.artifWorn = h->artifWorn; sha.artifWorn = h->artifWorn;
sha.artifWorn[17] = 0; VLC->arth->equipArtifact(sha.artifWorn, 17, 0);
sendAndApply(&sha); sendAndApply(&sha);
} }
@ -3063,9 +3079,9 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
sha.hid = hero->id; sha.hid = hero->id;
sha.artifacts = hero->artifacts; sha.artifacts = hero->artifacts;
sha.artifWorn = hero->artifWorn; sha.artifWorn = hero->artifWorn;
sha.artifWorn[13] = 4; VLC->arth->equipArtifact(sha.artifWorn, 13, 4);
sha.artifWorn[14] = 5; VLC->arth->equipArtifact(sha.artifWorn, 14, 5);
sha.artifWorn[15] = 6; VLC->arth->equipArtifact(sha.artifWorn, 15, 6);
sendAndApply(&sha); sendAndApply(&sha);
} }
else if(message == "vcminahar") //1000000 movement points else if(message == "vcminahar") //1000000 movement points