1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merged Warmonger's changes from trunk

This commit is contained in:
Michał W. Urbańczyk 2011-02-06 08:32:05 +00:00
commit 31fc8f6db3
12 changed files with 325 additions and 39 deletions

View File

@ -17,7 +17,7 @@ void CEmptyAI::heroKilled(const CGHeroInstance *)
void CEmptyAI::heroCreated(const CGHeroInstance *)
{
}
void CEmptyAI::heroMoved(const HeroMoveDetails &)
void CEmptyAI::heroMoved(const TryMoveHero& TMH)
{
}
void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)

View File

@ -11,7 +11,7 @@ public:
void yourTurn();
void heroKilled(const CGHeroInstance *);
void heroCreated(const CGHeroInstance *);
void heroMoved(const HeroMoveDetails &);
void heroMoved(const TryMoveHero&);
void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) {};
void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
void tileRevealed(int3 pos){};

View File

@ -14,9 +14,9 @@
template <typename ruleType, typename facts> template <typename cond> void ExpertSystemShell<ruleType, facts>::DataDrivenReasoning(runType type)
{
std::set<ruleType>::iterator ir;
std::vector<ruleType>::iterator ir;
std::list<fact>::iterator iF;
std::set<std::pair<cond, input*>>::iterator ic;
std::vector<std::pair<cond, input*>>::iterator ic;
bool factWasAdded = false; //carry it over inner loop
switch (type)
{
@ -72,7 +72,7 @@ template <typename ruleType, typename facts> template <typename cond> void Exper
}
void BonusRule::fireRule()
{
for (std::set<std::pair<BonusCondition, BonusHolder*>>::iterator it = cons.begin(); it != cons.end(); it++)
for (std::vector<std::pair<BonusCondition, BonusHolder*>>::iterator it = cons.begin(); it != cons.end(); it++)
{
switch (it->first.parameter)
{ //compare fact with condition
@ -109,18 +109,31 @@ void BonusRule::fireRule()
}
//TODO: add new fact or modify existing one
}
//TODO: find out why it does not compile
//template <typename input, typename conType> void Rule<input, conType>::refreshRule(std::set<conType> &conditionSet)
//{
// cons.clear();
// for (std::set<conType>::iterator it = conditionSet.begin(); it != conditionSet.end(); it++)
// cons.insert(std::make_pair<conType,input*>(*it, NULL)); //pointer to condition and null fact
//}
//template <typename input, typename conType> void Rule<input, conType>::refreshRule()
//{
// for (std::set<std::pair<conType, input*>>::iterator it = cons.begin(); it != cons.end(); it++)
// *it->second = NULL;
//}
TLogic operator&&(const TLogic &first, const TLogic &second)
{
return LogicConjunction(first, second);
}
TLogic operator||(const TLogic &first, const TLogic &second)
{
return LogicAlternative(first, second);
}
template <typename input, typename conType> void Rule<input, conType>::refreshRule(std::vector<conType> &conditionSet)
{//replace conditions with new vector
cons.clear();
std::pair <conType,input*> para;
para.second = NULL;
for (std::vector<conType>::iterator it = conditionSet.begin(); it != conditionSet.end(); it++)
{
para.first = *it;
cons.push_back(para); //pointer to condition and null fact
}
}
template <typename input, typename conType> void Rule<input, conType>::refreshRule()
{//clear matching facts
for (std::vector<std::pair<conType, input*>>::iterator it = cons.begin(); it != cons.end(); it++)
it->second = NULL;
}
bool BonusCondition::matchesFact(Bonus &fact)
{
if (object(fact)) //Bonus(fact) matches local Selector(object)

View File

@ -2,7 +2,7 @@
#include "../vcmi/CCallback.h"
#include "../vcmi/lib/HeroBonus.h"
#include <boost/bind.hpp>
#include <set>
#include <vector>
/*
* ExpertSystem.h, part of VCMI engine
@ -17,21 +17,22 @@ struct Bonus;
template <typename fact> class AIholder;
template <typename input, typename output> class Rule;
typedef Rule<Bonus, Bonus> BRule;
typedef boost::function<bool(int, si32)> TLogic;
bool greaterThan (int prop, si32 val);
enum conditionType {LESS_THAN, EQUAL, GREATER_THAN, UNEQUAL, PRESENT};
template <typename ruleType, typename fact> class ExpertSystemShell
{
enum runType {ANY_GOAL, TRESHOLD, FULL};
enum runType {ANY_GOAL, TRESHOLD, FULL}; //Treshold - stop when received decision has high AI value
private:
ICallback* m_cb;
protected:
std::set<ruleType> knowledge;
std::set<ruleType*> rulesToErase;
std::set<ruleType*> rulesToAdd;
std::set<fact*> factsToErase;
std::set<fact*> factsToAdd;
std::vector<ruleType> knowledge;
std::vector<ruleType*> rulesToErase;
std::vector<ruleType*> rulesToAdd;
std::vector<fact*> factsToErase;
std::vector<fact*> factsToAdd;
ui16 goalCounter; //count / evaluate achieved goals for runType
public:
ExpertSystemShell(){goalCounter = 0;};
@ -53,12 +54,12 @@ public:
};
template <typename input> class condition
{//compares selected object parameter with value using functor. universal logic handler
{//compares selected object parameter with value using functor. universal (?) logic handler
public:
input object; //what the fact is, or what it's like (CSelector)
si32 value;
ui8 parameter;
boost::function<bool(int,si32)> functor; //value of selected parameter, condition value
TLogic functor; //value of selected parameter, condition value
condition(){object = NULL; value = 0; parameter = 0; functor = greaterThan;};
@ -72,16 +73,16 @@ public:
bool fired; //if conditions of rule were met and it produces some output
ui8 conditionCounter;
protected:
std::set<std::pair<conType, input*>> cons; //conditions and matching facts
std::vector<std::pair<conType, input*>> cons; //conditions and matching facts
input decision;
virtual void canBeFired(); //if this data makes any sense for rule - type check
virtual bool checkCondition(); //if condition is true or false
virtual bool checkCondition(std::set<input*> &feed);
virtual bool checkCondition(std::vector<input*> &feed);
virtual void fireRule(); //use paired conditions and facts by default
virtual void fireRule(ExpertSystemShell<input, conType> &system);
virtual void fireRule(std::set<input*> &feed);
virtual void fireRule(std::vector<input*> &feed);
virtual void refreshRule();
virtual void refreshRule(std::set<conType> &conditionSet); //in case conditions were erased
virtual void refreshRule(std::vector<conType> &conditionSet); //in case conditions were erased
public:
Rule(){fired = false; conditionCounter = 0; decision = NULL;};
template <typename givenInput> bool matchesInput() //if condition and data match type
@ -142,7 +143,7 @@ protected:
void fireRule();
};
inline bool greaterThan (int prop, si32 val)
inline bool greaterThan (int prop, si32 val) //does it make any sense to keep functors inline?
{
if ((si32)prop > val)
return true;
@ -172,6 +173,36 @@ inline bool present (int prop, si32 val=0)
return(prop); //unfixable warning :(
}
class LogicConjunction
{
const TLogic first, second; //TODO: universal argument list of functions?
public:
LogicConjunction(const TLogic First, const TLogic Second)
:first(First), second(Second)
{
}
bool operator()(int prop, si32 val) const
{
return first(prop,val) && second(prop,val);
}
};
TLogic operator&&(const TLogic &first, const TLogic &second);
class LogicAlternative
{
const TLogic first, second;
public:
LogicAlternative(const TLogic First, const TLogic Second)
:first(First), second(Second)
{
}
bool operator()(int prop, si32 val) const
{
return first(prop,val) || second(prop,val);
}
};
TLogic operator||(const TLogic &first, const TLogic &second);
class KnowledgeHandler///I'd opt for one omniscent knowledge manager, so no templates here
{
public:

View File

@ -46,6 +46,7 @@ void CMediaHandler::extract(int index, std::string dstfile) //saves selected fil
void CMediaHandler::extract(std::string srcfile, std::string dstfile, bool caseSens) //saves selected file
{
srcfile.erase(srcfile.find_last_of('.'));
if (caseSens)
{
for (size_t i=0;i<entries.size();++i)

41
config/bonusnames.txt Normal file
View File

@ -0,0 +1,41 @@
Bonus Name (24 characters?) Description
FLYING Fly Can Fly (ignores obstacles)
UNLIMITED_RETALIATIONS Unlimited retaliations May retaliate any number of attacks
SHOOTER Ranged Creature can make a Ranged Attack
FREE_SHOOTING Shoot Close Can make a Ranged Attack in Close Combat
NO_SHOTING_PENALTY ? ???
NO_MELEE_PENALTY No melee penalty Creature has no Melee Penalty
NO_DISTANCE_PENALTY No distance penalty Does full ranged damage from any distance
NO_OBSTACLES_PENALTY No obstacle penalty Creature has no Obstacle Penalty
JOUSTING Champion Champion Distance Bonus (+5% damage per square travelled)
RETURN_AFTER_STRIKE Attack and Return Returns to starting position after making a melee attack
BLOCKS_RETALIATION No retaliation Enemy cannot Retaliate
TWO_HEX_ATTACK_BREATH Breath Creature has a Breath Attack (2-hex range)
THREE_HEADED_ATTACK Three-headed attack Creature attacks three adjacent units
ATTACKS_ALL_ADJACENT Attack all around Creature attacks all adjacent enemies
FULL_HP_REGENERATION Regeneration May Regenerate full Health
LIFE_DRAIN Drain life Drains life equal to damage dealt
SELF_MORALE Positive morale Always has Positive Morale
SELF_LUCK Positive luck Always has Positive Luck
FEAR Fear Has a chance to cause Fear on an enemy stack
FEARLESS Fearless Immune to Fear ability
CHARGE_IMMUNITY Immune to Charge Immune to Champion charge bonus
HEALER Healer Heals allied units
CATAPULT Catapult Attacks siege walls
DRAGON_NATURE Dragon Creature has a Dragon Nature
NON_LIVING Non living Creature is immune to effects affecting Living units
UNDEAD Undead Creature is Undead
HATE Hates %s Does more damage to %s
DOUBLE_DAMAGE_CHANCE Death Blow Has %d% chance to deal double damage
MAGIC_RESISTANCE Magic Resistance Has %d% chance to resist enemy spell
SPELL_DAMAGE_REDUCTION Spell Resistance Damage from spells reduced 50%.
LEVEL_SPELL_IMMUNITY Spell immunity 1-%d Immune to spells levels 1-%d
HP_REGENERATION Regeneration Heals %d hit points every round
SPELL_IMMUNITY Immune to %s Immune to %s spell
ENEMY_DEFENCE_REDUCTION Reduces Enemy Defense Reduces Enemy Defense by %d% for this attack
MAGIC_MIRROR Magic Mirror Has %d% chance to redirect offensive spell back to enemy
ADDITIONAL_RETALIATION Additional retaliations May Retaliate %d extra times
CHANGES_SPELL_COST_FOR_ALLY Reduce Casting Cost Reduce Casting Cost of allied hero spells by %d
CHANGES_SPELL_COST_FOR_ENEMY Magic Damper Increase Casting Cost of enemy hero spells by %d
MANA_CHANNELING Magic Channel %d% mana spent by enemy is transfered to your hero
SPELL_AFTER_ATTACK Caster - %s %d% chance to cast %s after attack

View File

@ -20,7 +20,8 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
typedef si64 expType;
typedef ui16 spelltype;
typedef std::pair<ui32, ui32> TDmgRange;
typedef ui8 TBonusType;
typedef si32 TBonusSubtype;
#include "int3.h"
#include <map>
#include <vector>
@ -117,11 +118,12 @@ const int NAMES_PER_TOWN=16;
const int CREATURES_PER_TOWN = 7; //without upgrades
const int MAX_BUILDING_PER_TURN = 1;
const int SPELL_LEVELS = 5;
//const int CREEP_SIZE = 4000; // neutral stacks won't grow beyon this number
//const int CREEP_SIZE = 4000; // neutral stacks won't grow beyond this number
const int CREEP_SIZE = 2000000000;
const int WEEKLY_GROWTH = 10; //percent
const int AVAILABLE_HEROES_PER_PLAYER = 2;
const bool DWELLINGS_ACCUMULATE_CREATURES = true;
const bool STACK_EXP = true;
const int BFIELD_WIDTH = 17;
const int BFIELD_HEIGHT = 11;

View File

@ -12,6 +12,7 @@
#include <boost/algorithm/string/replace.hpp>
#include "../lib/VCMI_Lib.h"
#include "../lib/CGameState.h"
#include <boost/foreach.hpp>
using namespace boost::assign;
extern CLodHandler * bitmaph;
@ -590,6 +591,69 @@ void CCreatureHandler::loadCreatures()
inp3 >> factionToTurretCreature[g];
}
inp3.close();
//reading creature ability names
ifs.open(DATA_DIR "/config/bonusnames.txt");
{
std::string buf2, buf3, line;
int i;
std::map<std::string,int>::const_iterator it;
getline(ifs, line); //skip 1st line
while(!ifs.eof())
{
getline(ifs, buf, '\t');
getline(ifs, buf2, '\t');
getline(ifs, buf3);
it = bonusNameMap.find(buf);
if (it != bonusNameMap.end())
stackBonuses[it->second] = std::pair<std::string, std::string>(buf2,buf3);
else
tlog2 << "Bonus " << buf << " not recognized, ingoring\n";
}
}
ifs.close();
if (STACK_EXP) //reading default stack experience bonuses
{
buf = bitmaph->getTextFile("CREXPBON.TXT");
int it = 0;
si32 creid = -1;
commonBonuses.resize(8); //8 tiers
stackExperience b;
b.expBonuses.resize(10);
b.source = Bonus::STACK_EXPERIENCE;
loadToIt (dump2, buf, it, 3); //ignore first line
loadToIt (dump2, buf, it, 4); //ignore index
loadStackExp(b, buf, it);
loadToIt (dump2, buf, it, 4); //crop comment
for (i = 0; i < 8; ++i)
{
commonBonuses[i].push_back(new stackExperience(b));//health bonus common for all
for (int j = 0; j < 4; ++j) //four modifiers common for tiers
{
loadToIt (dump2, buf, it, 4); //ignore index
loadStackExp(b, buf, it);
commonBonuses[i].push_back(new stackExperience(b));
loadToIt (dump2, buf, it, 3); //crop comment
}
}
do //parse everything that's left
{
loadToIt(creid, buf, it, 4); //get index
loadStackExp(b, buf, it);
creatures[creid]->bonuses.push_back(new stackExperience(b)); //experience list is common for creatures of that type
loadToIt (dump2, buf, it, 3); //crop comment
} while (it < buf.size());
BOOST_FOREACH(CCreature *c, creatures)
{
if (it = c->level < 7)
std::copy(commonBonuses[it-1].begin(), commonBonuses[it-1].end(), c->bonuses.begin());
else
std::copy(commonBonuses[7].begin(), commonBonuses[7].end(), c->bonuses.begin()); //common for tiers 8+
}
} //end of stack experience
}
void CCreatureHandler::loadAnimationInfo()
@ -662,6 +726,40 @@ void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, std::string & src, int
i+=2;
}
void CCreatureHandler::loadStackExp(stackExperience & b, std::string & src, int & it) //help function for parsing CREXPBON.txt, assuming all its details are already defined
{
std::string buf, mod;
loadToIt(buf, src, it, 4);
loadToIt(mod, src, it, 4);
switch (buf[0])
{
case 'H':
b.type = Bonus::STACK_HEALTH;
break;
case 'A':
b.type = Bonus::PRIMARY_SKILL;
b.subtype = PrimarySkill::ATTACK;
break;
case 'D':
b.type = Bonus::PRIMARY_SKILL;
b.subtype = PrimarySkill::DEFENSE;
break;
case 'M': //Max damage
b.type = Bonus::CREATURE_DAMAGE;
b.subtype = 2;
break;
case 'm': //Min damage
b.type = Bonus::CREATURE_DAMAGE;
b.subtype = 1;
break;
}
loadToIt (b.val, src, it, 4); //basic value, not particularly useful but existent
for (int i = 0; i < 10; ++i)
{
loadToIt (b.expBonuses[i], src, it, 4); //vector must have length 10
}
}
CCreatureHandler::~CCreatureHandler()
{
}

View File

@ -113,9 +113,13 @@ public:
std::vector<si8> factionAlignments; //1 for good, 0 for neutral and -1 for evil with faction ID as index
int factionToTurretCreature[F_NUMBER]; //which creature's animation should be used to dispaly creature in turret while siege
std::map<TBonusType, std::pair<std::string, std::string> > stackBonuses; // bonus => name, description
std::vector<BonusList> commonBonuses; // levels 1-8 from CREXPBON.txt
void loadCreatures();
void loadAnimationInfo();
void loadUnitAnimInfo(CCreature & unit, std::string & src, int & i);
void loadStackExp(stackExperience & b, std::string & src, int & it);
bool isGood (si8 faction) const;
bool isEvil (si8 faction) const;

View File

@ -8,6 +8,9 @@
#include "CGameState.h"
#include "CGeneralTextHandler.h"
#include <sstream>
#include "CSpellHandler.h"
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/replace.hpp>
const CStackInstance &CCreatureSet::operator[](TSlot slot) const
{
@ -441,6 +444,100 @@ void CStackInstance::setType(const CCreature *c)
attachTo(const_cast<CCreature*>(type));
}
std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
{
std::map<TBonusType, std::pair<std::string, std::string>>::iterator it = VLC->creh->stackBonuses.find(bonus->type);
if (it != VLC->creh->stackBonuses.end())
{
std::string text;
if (description) //long ability description
{
text = it->second.second;
switch (bonus->type)
{
//no additional modifiers needed
case Bonus::FLYING:
case Bonus::UNLIMITED_RETALIATIONS:
case Bonus::SHOOTER:
case Bonus::FREE_SHOOTING:
case Bonus::NO_SHOTING_PENALTY:
case Bonus::NO_MELEE_PENALTY:
case Bonus::NO_DISTANCE_PENALTY:
case Bonus::NO_OBSTACLES_PENALTY:
case Bonus::JOUSTING: //TODO: percent bonus?
case Bonus::RETURN_AFTER_STRIKE:
case Bonus::BLOCKS_RETALIATION:
case Bonus::TWO_HEX_ATTACK_BREATH:
case Bonus::THREE_HEADED_ATTACK:
case Bonus::ATTACKS_ALL_ADJACENT:
case Bonus::FULL_HP_REGENERATION:
case Bonus::LIFE_DRAIN: //TODO: chance, hp percentage?
case Bonus::SELF_MORALE:
case Bonus::SELF_LUCK:
case Bonus::FEAR:
case Bonus::FEARLESS:
case Bonus::CHARGE_IMMUNITY:
case Bonus::HEALER:
case Bonus::CATAPULT:
case Bonus::DRAGON_NATURE:
case Bonus::NON_LIVING:
case Bonus::UNDEAD:
break;
//One numeric value
//case Bonus::STACKS_SPEED: //Do we need description for creature stats?
//case Bonus::STACK_HEALTH:
case Bonus::MAGIC_RESISTANCE:
case Bonus::SPELL_DAMAGE_REDUCTION:
case Bonus::LEVEL_SPELL_IMMUNITY:
case Bonus::CHANGES_SPELL_COST_FOR_ALLY:
case Bonus::CHANGES_SPELL_COST_FOR_ENEMY:
case Bonus::MANA_CHANNELING:
case Bonus::MANA_DRAIN:
case Bonus::HP_REGENERATION:
case Bonus::ADDITIONAL_RETALIATION:
case Bonus::DOUBLE_DAMAGE_CHANCE:
case Bonus::ENEMY_DEFENCE_REDUCTION:
case Bonus::MAGIC_MIRROR:
case Bonus::DARKNESS: //Darkness Dragons any1?
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
break;
//Complex descriptions
case Bonus::HATE: //TODO: customize damage percent
boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
break;
case Bonus::SPELL_IMMUNITY:
boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
break;
case Bonus::SPELL_AFTER_ATTACK:
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->additionalInfo % 100));
boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
break;
default:
{}//TODO: allow custom bonus types... someday, somehow
}
}
else //short name
{
text = it->second.first;
switch (bonus->type)
{
case Bonus::HATE:
boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
break;
case Bonus::LEVEL_SPELL_IMMUNITY:
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
break;
case Bonus::SPELL_IMMUNITY:
case Bonus::SPELL_AFTER_ATTACK:
boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
break;
}
}
return text;
}
else
return "";
}
void CStackInstance::setArmyObj(const CArmedInstance *ArmyObj)
{

View File

@ -45,6 +45,7 @@ public:
//overrides CBonusSystemNode
//void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const; //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
std::string bonusToString(Bonus *bonus, bool description) const; // how would bonus description look for this particular type of node
int getQuantityID() const;
std::string getQuantityTXT(bool capitalized = true) const;

View File

@ -16,10 +16,6 @@
*
*/
typedef ui8 TBonusType;
typedef si32 TBonusSubtype;
class CCreature;
class CSpell;
struct Bonus;
@ -159,7 +155,7 @@ namespace PrimarySkill
BONUS_NAME(MAXED_SPELL) /*val = id*/\
BONUS_NAME(SPECIAL_PECULIAR_ENCHANT) /*blesses and curses with id = val dependent on unit's level, subtype = 0 or 1 for Coronius*/\
BONUS_NAME(SPECIAL_UPGRADE) /*val = base, additionalInfo = target */\
BONUS_NAME(DRAGON_NATURE) /*TODO: implement it!*/\
BONUS_NAME(DRAGON_NATURE) \
BONUS_NAME(CREATURE_DAMAGE)/*subtype 0 = both, 1 = min, 2 = max*/
struct DLL_EXPORT Bonus
@ -198,6 +194,7 @@ struct DLL_EXPORT Bonus
ARMY,
CAMPAIGN_BONUS,
SPECIAL_WEEK,
STACK_EXPERIENCE,
OTHER /*used for defensive stance*/
};
@ -309,7 +306,7 @@ struct DLL_EXPORT Bonus
struct DLL_EXPORT stackExperience : public Bonus
{
std::vector<ui32> expBonuses; // variations for levels 1-10, copied to val field;
std::vector<si32> expBonuses; // variations for levels 1-10, copied to val field;
bool enable; //if true - turns ability on / off for zero value
template <typename Handler> void serialize(Handler &h, const int version)
@ -382,6 +379,7 @@ public:
void getParents(TCNodes &out) const; //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
virtual std::string bonusToString(Bonus *bonus, bool description) const {return "";}; //description or bonus name
//////////////////////////////////////////////////////////////////////////
//interface