1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00
Support for commander artifacts that accumulate bonus after battle.
This commit is contained in:
DjWarmonger 2012-07-16 16:18:02 +00:00
parent 69de38bf1d
commit cf45239332
10 changed files with 408 additions and 231 deletions

View File

@ -542,7 +542,7 @@ void CCreatureWindow::showAll(SDL_Surface * to)
skillPictures[i]->showAll (to);
}
if (upgradeOptions[selectedOption] >= 100) //add frame to selected skill
if (type == COMMANDER_LEVEL_UP && upgradeOptions[selectedOption] >= 100) //add frame to selected skill
{
int index = selectedOption - selectableSkills.size(); //this is screwed
CSDL_Ext::drawBorder(to, Rect::around(selectableBonuses[index]->pos), int3(Colors::MetallicGold.r, Colors::MetallicGold.g, Colors::MetallicGold.b));

View File

@ -51,5 +51,86 @@
{"ability": ["JOUSTING", 0, 0, 0 ], "skills": [3, 4]},
{"ability": ["DEATH_STARE", 1, 1, 0 ], "skills": [3,5]},
{"ability": ["FLYING", 0, 0, 0 ], "skills": [4,5]}
],
"artifacts":
[
{
"id": 146, //axe of smashing
"bonusesPerLevel":
[
{
"level": 6,
"bonus": ["PRIMARY_SKILL", 1, 0, 0]
}
]
},
{
"id": 147, //mithril mail
"bonusesPerLevel":
[
{
"level": 1,
"bonus": ["STACK_HEALTH", 1, 0, 0]
}
]
},
{
"id": 148, //sword of sharpness
"bonusesPerLevel":
[
{
"level": 1,
"bonus": ["CREATURE_DAMAGE", 1, 0, 0]
}
]
},
{
"id": 150, //pendant of sorcery
"bonusesPerLevel":
[
{
"level": 10,
"bonus": ["CREATURE_ENCHANT_POWER", 1, 0, 0]
}
]
},
{
"id": 151, //boots of haste
"bonusesPerLevel":
[
{
"level": 10,
"bonus": ["STACKS_SPEED", 1, 0, 0]
}
]
},
{
"id": 152, //bow of seeking
"thresholdBonuses":
[
{
"level": 5,
"bonus": ["SHOOTER", 0, 0, 0]
},
{
"level": 25,
"bonus": ["NO_WALL_PENALTY", 0, 0, 0]
},
{
"level": 50,
"bonus": ["NO_DISTANCE_PENALTY", 0, 0, 0]
}
]
},
{
"id": 153, //hardened shield
"bonusesPerLevel":
[
{
"level": 6,
"bonus": ["PRIMARY_SKILL", 1, 1, 0]
}
]
}
]
}

View File

@ -8,6 +8,7 @@
#include "CSpellHandler.h"
#include "CObjectHandler.h"
#include "NetPacks.h"
#include "../lib/JsonNode.h"
extern CLodHandler *bitmaph;
using namespace boost::assign;
@ -23,6 +24,7 @@ using namespace boost::assign;
*/
extern boost::rand48 ran;
extern Bonus * ParseBonus (const JsonVector &ability_vec);
const std::string & CArtifact::Name() const
{
@ -44,11 +46,6 @@ bool CArtifact::isBig () const
{
return VLC->arth->isBigArtifact(id);
}
//
// bool CArtifact::isModable () const
// {
// return (bool)dynamic_cast<const IModableArt *>(this);
// }
// /**
// * Checks whether the artifact fits at a given slot.
@ -193,6 +190,30 @@ void CArtifact::setDescription (std::string desc)
description = desc;
}
void CGrowingArtifact::levelUpArtifact (CArtifactInstance * art)
{
Bonus b;
b.type = Bonus::LEVEL_COUNTER;
b.val = 1;
b.duration = Bonus::COMMANDER_KILLED;
art->accumulateBonus (b);
BOOST_FOREACH (auto bonus, bonusesPerLevel)
{
if (art->valOfBonuses(Bonus::LEVEL_COUNTER) % bonus.first == 0) //every n levels
{
art->accumulateBonus (bonus.second);
}
}
BOOST_FOREACH (auto bonus, thresholdBonuses)
{
if (art->valOfBonuses(Bonus::LEVEL_COUNTER) == bonus.first) //every n levels
{
art->addNewBonus (&bonus.second);
}
}
}
CArtHandler::CArtHandler()
{
VLC->arth = this;
@ -215,6 +236,7 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
{
std::vector<ui16> slots;
slots += 17, 16, 15, 14, 13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0;
growingArtifacts += 146, 147, 148, 150, 151, 152, 153;
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);
std::string buf = bitmaph->getTextFile("ARTRAITS.TXT"), dump, pom;
@ -226,10 +248,18 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
VLC->generaltexth->artifNames.resize(GameConstants::ARTIFACTS_QUANTITY);
VLC->generaltexth->artifDescriptions.resize(GameConstants::ARTIFACTS_QUANTITY);
std::map<ui32,ui8>::iterator itr;
for (int i=0; i<GameConstants::ARTIFACTS_QUANTITY; i++)
{
CArtifact *art = new CArtifact();
CArtifact *art;
if (vstd::contains (growingArtifacts, i))
{
art = new CGrowingArtifact();
}
else
{
art = new CArtifact();
}
CArtifact &nart = *art;
nart.id=i;
loadToIt(VLC->generaltexth->artifNames[i],buf,it,4);
@ -329,6 +359,23 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
artifacts.push_back(&nart);
}
if (GameConstants::COMMANDERS)
{ //TODO: move all artifacts config to separate json file
const JsonNode config(GameConstants::DATA_DIR + "/config/commanders.json");
BOOST_FOREACH(const JsonNode &artifact, config["artifacts"].Vector())
{
auto ga = dynamic_cast <CGrowingArtifact *>(artifacts[artifact["id"].Float()].get());
BOOST_FOREACH (auto b, artifact["bonusesPerLevel"].Vector())
{
ga->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *ParseBonus (b["bonus"].Vector())));
}
BOOST_FOREACH (auto b, artifact["thresholdBonuses"].Vector())
{
ga->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *ParseBonus (b["bonus"].Vector())));
}
}
}
sortArts();
if(onlyTxt)
return;
@ -1112,7 +1159,17 @@ void CArtifactInstance::move(ArtifactLocation src, ArtifactLocation dst)
CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
{
if(!Art->constituents)
return new CArtifactInstance(Art);
{
auto ret = new CArtifactInstance(Art);
if (dynamic_cast<CGrowingArtifact *>(Art))
{
Bonus * bonus = new Bonus;
bonus->type = Bonus::LEVEL_COUNTER;
bonus->val = 0;
ret->addNewBonus (bonus);
}
return ret;
}
else
{
CCombinedArtifactInstance * ret = new CCombinedArtifactInstance(Art);

View File

@ -18,6 +18,7 @@ class CArtifact;
class CGHeroInstance;
struct ArtifactLocation;
class CArtifactSet;
class CArtifactInstance;
namespace ArtifactPosition
{
@ -55,6 +56,8 @@ public:
int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other
std::string nodeName() const OVERRIDE;
virtual void levelUpArtifact (CArtifactInstance * art){};
ui32 price;
bmap<ui8, std::vector<ui16> > possibleSlots; //Bearer Type => ids of slots where artifact can be placed
std::vector<ui32> * constituents; // Artifacts IDs a combined artifact consists of, or NULL.
@ -75,6 +78,21 @@ public:
//void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
};
class DLL_LINKAGE CGrowingArtifact : public CArtifact //for example commander artifacts getting bonuses after battle
{
public:
std::vector <std::pair <ui16, Bonus> > bonusesPerLevel; //bonus given each n levels
std::vector <std::pair <ui16, Bonus> > thresholdBonuses; //after certain level they will be added once
void levelUpArtifact (CArtifactInstance * art);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArtifact&>(*this);
h & bonusesPerLevel & thresholdBonuses;
}
};
class DLL_LINKAGE CArtifactInstance : public CBonusSystemNode
{
protected:
@ -170,7 +188,7 @@ public:
std::vector< ConstTransitivePtr<CArtifact> > artifacts;
std::vector<CArtifact *> allowedArtifacts;
std::set<ui32> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
//std::map<ui32, ui8> modableArtifacts; //1-scroll, 2-banner, 3-commander art with progressive bonus
std::set<ui32> growingArtifacts;
void loadArtifacts(bool onlyTxt);
void sortArts();
@ -194,7 +212,8 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & artifacts & allowedArtifacts & treasures & minors & majors & relics;
h & artifacts & allowedArtifacts & treasures & minors & majors & relics
& growingArtifacts;
//if(!h.saving) sortArts();
}
};

View File

@ -202,24 +202,6 @@ bool CCreatureHandler::isEvil (si8 faction) const
{
return faction != -1 && factionAlignments[faction] == -1;
}
static Bonus * ParseBonus (const JsonVector &ability_vec) //TODO: merge with AddAbility, create universal parser for all bonus properties
{
Bonus * b = new Bonus();
std::string type = ability_vec[0].String();
auto it = bonusNameMap.find(type);
if (it == bonusNameMap.end())
{
tlog1 << "Error: invalid ability type " << type << " in creatures.txt" << std::endl;
return b;
}
b->type = it->second;
b->val = ability_vec[1].Float();
b->subtype = ability_vec[2].Float();
b->additionalInfo = ability_vec[3].Float();
b->duration = Bonus::PERMANENT;
b->turnsRemain = 0;
return b;
}
static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
{

View File

@ -1010,7 +1010,7 @@ void CCommanderInstance::setAlive (bool Alive)
alive = Alive;
if (!alive)
{
//remove all bonuses from artifacts
getBonusList().remove_if (Bonus::UntilCommanderKilled);
}
}

View File

@ -35,6 +35,7 @@ typedef boost::function<bool(const Bonus*)> CSelector;
#define BONUS_LIST \
BONUS_NAME(NONE) \
BONUS_NAME(LEVEL_COUNTER) /* for commander artifacts*/ \
BONUS_NAME(MOVEMENT) /*both water/land*/ \
BONUS_NAME(LAND_MOVEMENT) \
BONUS_NAME(SEA_MOVEMENT) \
@ -194,7 +195,8 @@ struct DLL_LINKAGE Bonus
N_DAYS = 32,
UNITL_BEING_ATTACKED = 64,/*removed after attack and counterattacks are performed*/
UNTIL_ATTACK = 128, /*removed after attack and counterattacks are performed*/
STACK_GETS_TURN = 256 /*removed when stack gets its turn - used for defensive stance*/
STACK_GETS_TURN = 256, /*removed when stack gets its turn - used for defensive stance*/
COMMANDER_KILLED = 512
};
enum BonusSource
{
@ -303,6 +305,10 @@ struct DLL_LINKAGE Bonus
{
return hb->duration & Bonus::UNITL_BEING_ATTACKED;
}
static bool UntilCommanderKilled(const Bonus *hb)
{
return hb->duration & Bonus::COMMANDER_KILLED;
}
static bool IsFrom(const Bonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter
{
return hb.source==source && (id==0xffffff || hb.sid==id);

View File

@ -1,6 +1,9 @@
#include "StdInc.h"
#include "JsonNode.h"
class Bonus;
const JsonNode JsonNode::nullNode;
JsonNode::JsonNode(JsonType Type):
@ -869,4 +872,4 @@ JsonValidator::JsonValidator(JsonNode &root, const JsonNode &schema, bool Minimi
if (schema.isNull())
addMessage("Schema not found!");
tlog3<<errors;
}
}

View File

@ -1,200 +1,221 @@
#pragma once
class JsonNode;
typedef std::map <std::string, JsonNode> JsonMap;
typedef std::vector <JsonNode> JsonVector;
class DLL_LINKAGE JsonNode
{
public:
enum JsonType
{
DATA_NULL,
DATA_BOOL,
DATA_FLOAT,
DATA_STRING,
DATA_VECTOR,
DATA_STRUCT
};
private:
union JsonData
{
bool Bool;
double Float;
std::string* String;
JsonVector* Vector;
JsonMap* Struct;
};
JsonType type;
JsonData data;
public:
//Create empty node
JsonNode(JsonType Type = DATA_NULL);
//Create tree from Json-formatted input
explicit JsonNode(const char * data, size_t datasize);
//Create tree from JSON file
explicit JsonNode(std::string filename);
//Copy c-tor
JsonNode(const JsonNode &copy);
~JsonNode();
void swap(JsonNode &b);
JsonNode& operator =(JsonNode node);
bool operator == (const JsonNode &other) const;
bool operator != (const JsonNode &other) const;
//removes all nodes that are identical to default entry in schema
void minimize(const JsonNode& schema);
//check schema
void validate(const JsonNode& schema);
//Convert node to another type. Converting to NULL will clear all data
void setType(JsonType Type);
JsonType getType() const;
bool isNull() const;
//non-const accessors, node will change type on type mismatch
bool & Bool();
double & Float();
std::string & String();
JsonVector & Vector();
JsonMap & Struct();
//const accessors, will cause assertion failure on type mismatch
const bool & Bool() const;
const double & Float() const;
const std::string & String() const;
const JsonVector & Vector() const;
const JsonMap & Struct() const;
template<typename T>
std::vector<T> StdVector() const
{
static_assert(std::is_arithmetic<T>::value, "This works with numbers only.");
#pragma once
#include "HeroBonus.h"
class JsonNode;
typedef std::map <std::string, JsonNode> JsonMap;
typedef std::vector <JsonNode> JsonVector;
class Bonus;
class DLL_LINKAGE JsonNode
{
public:
enum JsonType
{
DATA_NULL,
DATA_BOOL,
DATA_FLOAT,
DATA_STRING,
DATA_VECTOR,
DATA_STRUCT
};
private:
union JsonData
{
bool Bool;
double Float;
std::string* String;
JsonVector* Vector;
JsonMap* Struct;
};
JsonType type;
JsonData data;
public:
//Create empty node
JsonNode(JsonType Type = DATA_NULL);
//Create tree from Json-formatted input
explicit JsonNode(const char * data, size_t datasize);
//Create tree from JSON file
explicit JsonNode(std::string filename);
//Copy c-tor
JsonNode(const JsonNode &copy);
~JsonNode();
void swap(JsonNode &b);
JsonNode& operator =(JsonNode node);
bool operator == (const JsonNode &other) const;
bool operator != (const JsonNode &other) const;
//removes all nodes that are identical to default entry in schema
void minimize(const JsonNode& schema);
//check schema
void validate(const JsonNode& schema);
//Convert node to another type. Converting to NULL will clear all data
void setType(JsonType Type);
JsonType getType() const;
bool isNull() const;
//non-const accessors, node will change type on type mismatch
bool & Bool();
double & Float();
std::string & String();
JsonVector & Vector();
JsonMap & Struct();
//const accessors, will cause assertion failure on type mismatch
const bool & Bool() const;
const double & Float() const;
const std::string & String() const;
const JsonVector & Vector() const;
const JsonMap & Struct() const;
template<typename T>
std::vector<T> StdVector() const
{
static_assert(std::is_arithmetic<T>::value, "This works with numbers only.");
std::vector<T> ret;
BOOST_FOREACH(const JsonNode &node, Vector())
{
ret.push_back(node.Float());
}
return ret;
}
//operator [], for structs only - get child node by name
JsonNode & operator[](std::string child);
const JsonNode & operator[](std::string child) const;
//error value for const operator[]
static const JsonNode nullNode;
};
class JsonWriter
{
//prefix for each line (tabulation)
std::string prefix;
std::ostream &out;
public:
template<typename Iterator>
void writeContainer(Iterator begin, Iterator end);
void writeEntry(JsonMap::const_iterator entry);
void writeEntry(JsonVector::const_iterator entry);
void writeString(const std::string &string);
void writeNode(const JsonNode &node);
JsonWriter(std::ostream &output, const JsonNode &node);
};
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node);
//Tiny string class that uses const char* as data for speed, members are private
//for ease of debugging and some compatibility with std::string
class constString
{
const char *data;
const size_t datasize;
public:
constString(const char * inputString, size_t stringSize):
data(inputString),
datasize(stringSize)
{
}
inline size_t size() const
{
return datasize;
};
inline const char& operator[] (size_t position)
{
assert (position < datasize);
return data[position];
}
};
//Internal class for string -> JsonNode conversion
class JsonParser
{
std::string errors; // Contains description of all encountered errors
constString input; // Input data
ui32 lineCount; // Currently parsed line, starting from 1
size_t lineStart; // Position of current line start
size_t pos; // Current position of parser
//Helpers
bool extractEscaping(std::string &str);
bool extractLiteral(const std::string &literal);
bool extractString(std::string &string);
bool extractWhitespace(bool verbose = true);
bool extractSeparator();
bool extractElement(JsonNode &node, char terminator);
//Methods for extracting JSON data
bool extractArray(JsonNode &node);
bool extractFalse(JsonNode &node);
bool extractFloat(JsonNode &node);
bool extractNull(JsonNode &node);
bool extractString(JsonNode &node);
bool extractStruct(JsonNode &node);
bool extractTrue(JsonNode &node);
bool extractValue(JsonNode &node);
//Add error\warning message to list
bool error(const std::string &message, bool warning=false);
public:
JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
};
//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:
// - "schema" entry from root node is used for validation and will be removed
// - any missing entries will be replaced with default value from schema (if present)
// - if entry uses different type than defined in schema it will be removed
// - entries nod described in schema will be kept unchanged
class JsonValidator
{
std::string errors; // Contains description of all encountered errors
std::list<std::string> currentPath; // path from root node to current one
bool minimize;
bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type);
bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema);
bool validateNode(JsonNode &node, const JsonNode &schema, const std::string &name);
bool validateItems(JsonNode &node, const JsonNode &schema);
bool validateProperties(JsonNode &node, const JsonNode &schema);
bool addMessage(const std::string &message);
public:
// validate node with "schema" entry
JsonValidator(JsonNode &root, bool minimize=false);
// validate with external schema
JsonValidator(JsonNode &root, const JsonNode &schema, bool minimize=false);
};
}
return ret;
}
//operator [], for structs only - get child node by name
JsonNode & operator[](std::string child);
const JsonNode & operator[](std::string child) const;
//error value for const operator[]
static const JsonNode nullNode;
};
class JsonWriter
{
//prefix for each line (tabulation)
std::string prefix;
std::ostream &out;
public:
template<typename Iterator>
void writeContainer(Iterator begin, Iterator end);
void writeEntry(JsonMap::const_iterator entry);
void writeEntry(JsonVector::const_iterator entry);
void writeString(const std::string &string);
void writeNode(const JsonNode &node);
JsonWriter(std::ostream &output, const JsonNode &node);
};
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node);
//Tiny string class that uses const char* as data for speed, members are private
//for ease of debugging and some compatibility with std::string
class constString
{
const char *data;
const size_t datasize;
public:
constString(const char * inputString, size_t stringSize):
data(inputString),
datasize(stringSize)
{
}
inline size_t size() const
{
return datasize;
};
inline const char& operator[] (size_t position)
{
assert (position < datasize);
return data[position];
}
};
//Internal class for string -> JsonNode conversion
class JsonParser
{
std::string errors; // Contains description of all encountered errors
constString input; // Input data
ui32 lineCount; // Currently parsed line, starting from 1
size_t lineStart; // Position of current line start
size_t pos; // Current position of parser
//Helpers
bool extractEscaping(std::string &str);
bool extractLiteral(const std::string &literal);
bool extractString(std::string &string);
bool extractWhitespace(bool verbose = true);
bool extractSeparator();
bool extractElement(JsonNode &node, char terminator);
//Methods for extracting JSON data
bool extractArray(JsonNode &node);
bool extractFalse(JsonNode &node);
bool extractFloat(JsonNode &node);
bool extractNull(JsonNode &node);
bool extractString(JsonNode &node);
bool extractStruct(JsonNode &node);
bool extractTrue(JsonNode &node);
bool extractValue(JsonNode &node);
//Add error\warning message to list
bool error(const std::string &message, bool warning=false);
public:
JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
};
//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:
// - "schema" entry from root node is used for validation and will be removed
// - any missing entries will be replaced with default value from schema (if present)
// - if entry uses different type than defined in schema it will be removed
// - entries nod described in schema will be kept unchanged
class JsonValidator
{
std::string errors; // Contains description of all encountered errors
std::list<std::string> currentPath; // path from root node to current one
bool minimize;
bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type);
bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema);
bool validateNode(JsonNode &node, const JsonNode &schema, const std::string &name);
bool validateItems(JsonNode &node, const JsonNode &schema);
bool validateProperties(JsonNode &node, const JsonNode &schema);
bool addMessage(const std::string &message);
public:
// validate node with "schema" entry
JsonValidator(JsonNode &root, bool minimize=false);
// validate with external schema
JsonValidator(JsonNode &root, const JsonNode &schema, bool minimize=false);
};
//Bonus * ParseBonus (const JsonVector &ability_vec);
static Bonus * ParseBonus (const JsonVector &ability_vec) //TODO: merge with AddAbility, create universal parser for all bonus properties
{
Bonus * b = new Bonus();
std::string type = ability_vec[0].String();
auto it = bonusNameMap.find(type);
if (it == bonusNameMap.end())
{
tlog1 << "Error: invalid ability type " << type << " in creatures.txt" << std::endl;
return b;
}
b->type = it->second;
b->val = ability_vec[1].Float();
b->subtype = ability_vec[2].Float();
b->additionalInfo = ability_vec[3].Float();
b->duration = Bonus::PERMANENT;
b->turnsRemain = 0;
return b;
}

View File

@ -1032,6 +1032,8 @@ DLL_LINKAGE void BattleObstaclePlaced::applyGs( CGameState *gs )
void BattleResult::applyGs( CGameState *gs )
{
//stack with SUMMONED flag but coming from garrison -> most likely resurrected, needs to be removed
//TODO: switch commander status to dead
BOOST_FOREACH(CStack *s, gs->curB->stacks)
{
if(s->base && s->base->armyObj && vstd::contains(s->state, EBattleStackState::SUMMONED))
@ -1043,14 +1045,20 @@ void BattleResult::applyGs( CGameState *gs )
for (unsigned i = 0; i < gs->curB->stacks.size(); i++)
delete gs->curB->stacks[i];
//remove any "until next battle" bonuses
CGHeroInstance *h;
for (int i = 0; i < 2; ++i)
{
h = gs->curB->heroes[i];
h = gs->curB->heroes[i];
if (h)
{
h->getBonusList().remove_if(Bonus::OneBattle);
h->getBonusList().remove_if(Bonus::OneBattle); //remove any "until next battle" bonuses
if (h->commander && h->commander->alive)
{
BOOST_FOREACH (auto art, h->commander->artifactsWorn) //increment bonuses for commander artifacts
{
art.second.artifact->artType->levelUpArtifact (art.second.artifact);
}
}
}
}