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

* further changes towards luck/morale support

* partial support for Idol of Fortune, Fountain of Fortune, Faerie Ring, Swan Pond
This commit is contained in:
Michał W. Urbańczyk 2009-02-04 13:40:54 +00:00
parent 886ab94708
commit 218a3beaf6
15 changed files with 248 additions and 45 deletions

View File

@ -587,7 +587,8 @@ void CGameState::applyNL(IPack * pack)
{
GiveBonus *rh = static_cast<GiveBonus*>(pack);
CGHeroInstance *h = getHero(rh->hid);
h->bonuses.push_back(CGHeroInstance::Bonus(rh->bduration,rh->btype,rh->bval,rh->bid,toString(rh->bdescr)));
h->bonuses.push_back(rh->bonus);
h->bonuses.back().description = toString(rh->bdescr);
break;
}
case 500:

View File

@ -358,6 +358,16 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
for(int it=0; it < mrl.size(); it++)
morale->text += mrl[it].second;
mrl = hero->getCurrentLuckModifiers();
mrlv = hero->getCurrentLuck();
mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad luck, 0 - neutral, 1 - good
luck->hoverText = CGI->generaltexth->heroscrn[7 - mrlt];
luck->baseType = SComponent::luck;
luck->bonus = mrlv;
luck->text = CGI->generaltexth->arraytxt[62];
boost::algorithm::replace_first(luck->text,"%s",CGI->generaltexth->arraytxt[60-mrlt]);
for(int it=0; it < mrl.size(); it++)
luck->text += mrl[it].second;
pos.x += 65;
pos.y += 8;

View File

@ -155,21 +155,24 @@ const CArmedInstance * CGarrisonSlot::getObj()
return (!upg)?(owner->oup):(owner->odown);
}
StackState* getStackState(const CGObjectInstance *obj, int pos, bool town)
{
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(obj);
if(!h) return NULL;
StackState *pom = new StackState();
pom->currentHealth = 0;
pom->attackBonus = h->getPrimSkillLevel(0);
pom->defenseBonus = h->getPrimSkillLevel(1);
pom->luck = h->getCurrentLuck();
pom->morale = h->getCurrentMorale(pos,town);
return pom;
}
void CGarrisonSlot::clickRight (tribool down)
{
StackState *pom = NULL;
StackState *pom = getStackState(getObj(),ID,LOCPLINT->curint == LOCPLINT->castleInt);
if(down && creature)
{
if(getObj()->ID == 34)
{
pom = new StackState();
const CGHeroInstance *h = static_cast<const CGHeroInstance *>(getObj());
pom->currentHealth = 0;
pom->attackBonus = h->getPrimSkillLevel(0);
pom->defenseBonus = h->getPrimSkillLevel(1);
pom->luck = h->getCurrentLuck();
pom->morale = h->getCurrentMorale(ID);
}
(new CCreInfoWindow(creature->idNumber,0,count,pom,boost::function<void()>(),boost::function<void()>(),NULL))
->activate();
//LOCPLINT->curint->deactivate();
@ -190,11 +193,12 @@ void CGarrisonSlot::clickLeft(tribool down)
{
if(owner->highlighted == this) //view info
{
StackState *pom2 = getStackState(getObj(),ID,LOCPLINT->curint == LOCPLINT->castleInt);
UpgradeInfo pom = LOCPLINT->cb->getUpgradeInfo(getObj(),ID);
if(pom.oldID>=0)
{
(new CCreInfoWindow
(creature->idNumber,1,count,NULL,
(creature->idNumber,1,count,pom2,
boost::bind(&CCallback::upgradeCreature,LOCPLINT->cb,getObj(),ID,pom.newID[0]), //if upgrade is possible we'll bind proper function in callback
boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID),&pom))
->activate();
@ -202,7 +206,7 @@ void CGarrisonSlot::clickLeft(tribool down)
else
{
(new CCreInfoWindow
(creature->idNumber,1,count,NULL,0, boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID),NULL) )
(creature->idNumber,1,count,pom2,0, boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID),NULL) )
->activate();
}
if(LOCPLINT->curint->subInt)
@ -212,6 +216,7 @@ void CGarrisonSlot::clickLeft(tribool down)
owner->highlighted = NULL;
show();
refr = true;
delete pom2;
}
else if(!creature
&& (owner->splitting
@ -726,6 +731,9 @@ SDL_Surface * SComponent::getImg()
case morale:
return graphics->morale82->ourImages[val+3].bitmap;
break;
case luck:
return graphics->luck82->ourImages[val+3].bitmap;
break;
}
return NULL;
}

View File

@ -85,6 +85,8 @@ public:
void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb){}; //for hero<=>neutral army
void setAmount(int objid, ui32 val){};
void moveHero(int hid, int3 pos, bool instant){};
void giveHeroBonus(GiveBonus * bonus){};
void setMovePoints(SetMovePoints * smp){};
//////////////////////////////////////////////////////////////////////////
friend class CCallback; //handling players actions
friend void processCommand(const std::string &message, CClient *&client); //handling console

View File

@ -289,6 +289,8 @@ void CGeneralTextHandler::load()
while(itr<strs.length()-1)
{
loadToIt(tmp, strs, itr, 3);
if(tmp[0] == '"' && tmp[tmp.size()-1] == '"')
tmp = tmp.substr(1,tmp.size()-2);
arraytxt.push_back(tmp);
}

View File

@ -325,11 +325,6 @@ bool CGHeroInstance::canWalkOnSea() const
//TODO: write it - it should check if hero is flying, or something similiar
return false;
}
int CGHeroInstance::getCurrentLuck() const
{
//TODO: write it
return 0;
}
int CGHeroInstance::getPrimSkillLevel(int id) const
{
return primSkills[id];
@ -602,6 +597,10 @@ int CGHeroInstance::getCurrentMorale( int stack, bool town ) const
std::vector<std::pair<int,std::string> > mods = getCurrentMoraleModifiers(stack,town);
for(int i=0; i < mods.size(); i++)
ret += mods[i].first;
if(ret > 3)
return 3;
if(ret < -3)
return -3;
return ret;
}
@ -611,21 +610,34 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
std::vector<std::pair<int,std::string> > ret;
//various morale bonuses (from buildings, artifacts, etc)
for(std::list<Bonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == 2)
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == HeroBonus::MORALE)
ret.push_back(std::make_pair(i->val, i->description));
//leadership
if(getSecSkillLevel(6))
ret.push_back(std::make_pair(getSecSkillLevel(6),VLC->generaltexth->arraytxt[104+getSecSkillLevel(6)]));
//town structures
if(town && visitedTown)
{
if(visitedTown->subID == 0 && vstd::contains(visitedTown->builtBuildings,22)) //castle, brotherhood of sword built
ret.push_back(std::pair<int,std::string>(2,VLC->generaltexth->buildings[0][22].first + " +2"));
else if(vstd::contains(visitedTown->builtBuildings,5)) //tavern is built
ret.push_back(std::pair<int,std::string>(2,VLC->generaltexth->buildings[0][5].first + " +1"));
}
//number of alignments and presence of undead
if(stack>=0)
{
bool archangelInArmy = false;
std::set<si8> factions;
for(std::map<si32,std::pair<ui32,si32> >::const_iterator i=army.slots.begin(); i!=army.slots.end(); i++)
{
factions.insert(VLC->creh->creatures[i->second.first].faction);
if(i->second.first == 13)
archangelInArmy = true;
}
if(factions.size() == 1)
ret.push_back(std::pair<int,std::string>(1,VLC->generaltexth->arraytxt[115])); //All troops of one alignment +1
@ -645,11 +657,55 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
if(vstd::contains(factions,4))
ret.push_back(std::pair<int,std::string>(-1,VLC->generaltexth->arraytxt[116])); //Undead in group -1
if(archangelInArmy)
{
char buf[100];
sprintf(buf,VLC->generaltexth->arraytxt[117].c_str(),VLC->creh->creatures[13].namePl);
ret.push_back(std::pair<int,std::string>(-1,VLC->generaltexth->arraytxt[116])); //%s in group +1
}
}
return ret;
}
int CGHeroInstance::getCurrentLuck( int stack/*=-1*/, bool town/*=false*/ ) const
{
int ret = 0;
std::vector<std::pair<int,std::string> > mods = getCurrentLuckModifiers(stack,town);
for(int i=0; i < mods.size(); i++)
ret += mods[i].first;
if(ret > 3)
return 3;
if(ret < -3)
return -3;
return ret;
}
std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentLuckModifiers( int stack/*=-1*/, bool town/*=false*/ ) const
{
std::vector<std::pair<int,std::string> > ret;
//various morale bonuses (from buildings, artifacts, etc)
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == HeroBonus::LUCK)
ret.push_back(std::make_pair(i->val, i->description));
//luck skill
if(getSecSkillLevel(9))
ret.push_back(std::make_pair(getSecSkillLevel(9),VLC->generaltexth->arraytxt[73+getSecSkillLevel(9)]));
return ret;
}
const HeroBonus * CGHeroInstance::getBonus( int from, int id ) const
{
for (std::list<HeroBonus>::const_iterator i=bonuses.begin(); i!=bonuses.end(); i++)
if(i->source == from && i->id == id)
return &*i;
return NULL;
}
int CGTownInstance::getSightDistance() const //returns sight distance
{
return 10;
@ -1547,3 +1603,70 @@ void CGDwelling::initObj()
{
}
void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
{
bool visited = h->getBonus(HeroBonus::OBJECT,ID);
int messageID, bonusType, bonusVal;
InfoWindow iw;
iw.player = h->tempOwner;
switch(ID)
{
case 14: //swan pond
messageID = 29;
bonusType = HeroBonus::LUCK;
bonusVal = 2;
case 28: //Faerie Ring
messageID = 49;
bonusType = HeroBonus::LUCK;
bonusVal = 1;
break;
case 30: //fountain of fortune
messageID = 55;
bonusType = HeroBonus::LUCK;
bonusVal = rand()%5 - 1;
break;
case 38: //idol of fortune
messageID = 62;
bonusType = HeroBonus::IDOL_OF_FORTUNE_BONUS;
bonusVal = 1;
break;
}
if(visited)
{
messageID++;
}
else
{
iw.components.push_back(Component(9,0,1,0));
GiveBonus gbonus;
gbonus.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT, bonusVal, ID,"");
gbonus.hid = h->id;
gbonus.bdescr << std::pair<ui8,ui32>(6,71);
cb->giveHeroBonus(&gbonus);
if(ID==14) //swan pond - take all move points
{
SetMovePoints smp;
smp.hid = h->id;
smp.val = 0;
cb->setMovePoints(&smp);
}
}
iw.text << std::pair<ui8,ui32>(11,messageID);
cb->showInfoDialog(&iw);
}
const std::string & CGBonusingObject::getHoverText() const
{
const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
hoverName = VLC->generaltexth->names[ID];
if(h)
{
if(!h->getBonus(HeroBonus::OBJECT,ID))
hoverName += " " + VLC->generaltexth->allTexts[353]; //not visited
else
hoverName += " " + VLC->generaltexth->allTexts[352]; //visited
}
return hoverName;
}

View File

@ -7,6 +7,7 @@
#include <map>
#include <list>
#include "CCreatureHandler.h"
#include "../lib/HeroBonus.h"
#ifndef _MSC_VER
#include "CHeroHandler.h"
#include "CTownHandler.h"
@ -183,24 +184,7 @@ public:
}
} patrol;
struct DLL_EXPORT Bonus
{
ui8 duration; //0 - Permanent, 1 - OneBattle, 2 - OneDay, 3 - OneWeek
ui8 type; //0 - none, 1 - movement; 2 - morale; 3 - luck
si32 val;
ui32 id;
std::string description;
Bonus(ui8 Dur, ui8 Type, si32 Val, ui32 ID, std::string Desc)
:duration(Dur), type(Type), val(Val), id(ID), description(Desc)
{}
Bonus(){};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & duration & type & val & id;
}
};
std::list<Bonus> bonuses;
std::list<HeroBonus> bonuses;
//////////////////////////////////////////////////////////////////////////
@ -220,6 +204,7 @@ public:
}
//////////////////////////////////////////////////////////////////////////
const HeroBonus *getBonus(int from, int id) const;
const std::string &getBiography() const;
bool needsLastStack()const;
unsigned int getTileCost(const EterrainType & ttype, const Eroad & rdtype, const Eriver & rvtype) const;
@ -230,7 +215,8 @@ public:
int getSightDistance() const; //returns sight distance of this hero
si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
bool canWalkOnSea() const;
int getCurrentLuck() const;
int getCurrentLuck(int stack=-1, bool town=false) const;
std::vector<std::pair<int,std::string> > getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above
int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered
std::vector<std::pair<int,std::string> > getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above
int getPrimSkillLevel(int id) const;
@ -625,6 +611,18 @@ public:
}
};
class DLL_EXPORT CGBonusingObject : public CGObjectInstance //objects giving bonuses to luck/morale/movement
{
public:
void onHeroVisit(const CGHeroInstance * h) const;
const std::string & getHoverText() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_EXPORT CObjectHandler

26
lib/HeroBonus.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "../global.h"
#include <string>
struct DLL_EXPORT HeroBonus
{
enum BonusType{NONE, MOVEMENT, MORALE, LUCK, IDOL_OF_FORTUNE_BONUS};
enum BonusDuration{PERMANENT, ONE_BATTLE, ONE_DAY, ONE_WEEK};
enum BonusSource{ARTIFACT, OBJECT};
ui8 duration; //uses BonusDuration values
ui8 type; //uses BonusType values - says to what is this bonus
ui8 source;//uses BonusSource values - what gave that bonus
si32 val;//for morale/luck [-3,+3], others any
ui32 id; //id of object/artifact
std::string description;
HeroBonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc)
:duration(Dur), type(Type), source(Src), val(Val), id(ID), description(Desc)
{}
HeroBonus(){};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & duration & type & source & val & id & description;
}
};

View File

@ -6,6 +6,8 @@
#include <set>
#include "../client/FunctionList.h"
struct SetMovePoints;
struct GiveBonus;
class CGObjectInstance;
class CGTownInstance;
class CGHeroInstance;
@ -55,5 +57,7 @@ public:
virtual void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb)=0; //for hero<=>neutral army
virtual void setAmount(int objid, ui32 val)=0;
virtual void moveHero(int hid, int3 pos, bool instant)=0;
virtual void giveHeroBonus(GiveBonus * bonus)=0;
virtual void setMovePoints(SetMovePoints * smp)=0;
};
#endif // __IGAMECALLBACK_H__

View File

@ -2,6 +2,8 @@
#define __NETPACKS_H__
#include "../global.h"
#include "BattleAction.h"
#include "HeroBonus.h"
struct IPack
{
virtual ui16 getType()const = 0 ;
@ -194,16 +196,13 @@ struct GiveBonus : public CPack<GiveBonus> //115
{
GiveBonus(){type = 115;};
ui8 bduration;
ui8 btype;
si32 bval;
ui32 bid;
ui32 hid;
HeroBonus bonus;
MetaString bdescr;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & bduration & btype & bval & bid & hid & bdescr;
h & bonus & hid & bdescr;
}
};

View File

@ -392,6 +392,10 @@
RelativePath="..\hch\CTownHandler.h"
>
</File>
<File
RelativePath=".\HeroBonus.h"
>
</File>
<File
RelativePath=".\IGameCallback.h"
>

View File

@ -1777,6 +1777,14 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
loadQuest(guard, bufor, i);
break;
}
case 28: //faerie ring
case 14: //Swan pond
case 38: //idol of fortune
case 30: //Fountain of Fortune
{
nobj = new CGBonusingObject();
break;
}
case 214: //hero placeholder
{
i+=3; //TODO: handle it more properly

6
map.h
View File

@ -495,6 +495,12 @@ struct DLL_EXPORT Mapa : public CMapHeader
case 215:
SERIALIZE(CGQuestGuard);
break;
case 28: //faerie ring
case 14: //Swan pond
case 38: //idol of fortune
case 30: //Fountain of Fortune
SERIALIZE(CGBonusingObject);
break;
default:
SERIALIZE(CGObjectInstance);
}

View File

@ -2367,3 +2367,13 @@ void CGameHandler::sendMessageTo( CConnection &c, std::string message )
{
c << ui16(95) << message;
}
void CGameHandler::giveHeroBonus( GiveBonus * bonus )
{
sendAndApply(bonus);
}
void CGameHandler::setMovePoints( SetMovePoints * smp )
{
sendAndApply(smp);
}

View File

@ -103,6 +103,8 @@ public:
void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
void setAmount(int objid, ui32 val);
void moveHero(int hid, int3 pos, bool instant);
void giveHeroBonus(GiveBonus * bonus);
void setMovePoints(SetMovePoints * smp);
//////////////////////////////////////////////////////////////////////////
void init(StartInfo *si, int Seed);