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

* improved campaign handling - bonus selection screen is mostly functional

* preliminary support for giving campaign bonuses (resources and spells, artifacts, skills for generated hero are given)
* differing the amount of resources given to AI and human players
* minor changes
This commit is contained in:
mateuszb 2010-07-31 13:55:05 +00:00
parent 1338340027
commit c06de1f1ce
15 changed files with 232 additions and 87 deletions

View File

@ -15,10 +15,11 @@
*
*/
enum Ebonus {brandom=-1,bartifact, bgold, bresource};
struct PlayerSettings
{
enum Ebonus {brandom=-1,bartifact, bgold, bresource};
si32 castle, hero, //ID, if -1 then random, if -2 then none
heroPortrait; //-1 if default, else ID
std::string heroName;
@ -58,6 +59,7 @@ struct StartInfo
ui8 turnTime; //in minutes, 0=unlimited
std::string mapname;
ui8 whichMapInCampaign; //used only for mode 2
ui8 choosenCampaignBonus; //used only for mode 2
PlayerSettings & getIthPlayersSettings(int no)
{
for(unsigned int i=0; i<playerInfos.size(); ++i)
@ -84,6 +86,7 @@ struct StartInfo
h & turnTime;
h & mapname;
h & whichMapInCampaign;
h & choosenCampaignBonus;
}
};

View File

@ -255,7 +255,7 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
for(size_t g=0; g<std::min(secSkillAreas.size(),hero->secSkills.size()); ++g)
{
int skill = hero->secSkills[g].first,
level = hero->secSkills[g].second;
level = hero->getSecSkillLevel(hero->secSkills[g].first);
secSkillAreas[g]->type = skill;
secSkillAreas[g]->bonusValue = level;

View File

@ -1484,8 +1484,8 @@ void OptionsTab::nextCastle( int player, int dir )
if(s.hero >= 0)
s.hero = -1;
if(cur < 0 && s.bonus == bresource)
s.bonus = brandom;
if(cur < 0 && s.bonus == PlayerSettings::bresource)
s.bonus = PlayerSettings::brandom;
entries[player]->selectButtons();
redraw();
@ -1551,23 +1551,23 @@ void OptionsTab::nextBonus( int player, int dir )
PlayerSettings &s = curOpts->playerInfos[player];
si8 &ret = s.bonus += dir;
if (s.hero==-2 && !curMap->mapHeader->players[s.color].heroesNames.size() && ret==bartifact) //no hero - can't be artifact
if (s.hero==-2 && !curMap->mapHeader->players[s.color].heroesNames.size() && ret==PlayerSettings::bartifact) //no hero - can't be artifact
{
if (dir<0)
ret=brandom;
else ret=bgold;
ret=PlayerSettings::brandom;
else ret=PlayerSettings::bgold;
}
if(ret > bresource)
ret = brandom;
if(ret < brandom)
ret = bresource;
if(ret > PlayerSettings::bresource)
ret = PlayerSettings::brandom;
if(ret < PlayerSettings::brandom)
ret = PlayerSettings::bresource;
if (s.castle==-1 && ret==bresource) //random castle - can't be resource
if (s.castle==-1 && ret==PlayerSettings::bresource) //random castle - can't be resource
{
if (dir<0)
ret=bgold;
else ret=brandom;
ret=PlayerSettings::bgold;
else ret=PlayerSettings::brandom;
}
redraw();
@ -1932,20 +1932,20 @@ void OptionsTab::SelectedBox::clickRight( tribool down, bool previousState )
{
switch(val)
{
case brandom:
case PlayerSettings::brandom:
title = &CGI->generaltexth->allTexts[86]; //{Random Bonus}
description = &CGI->generaltexth->allTexts[94]; //Gold, wood and ore, or an artifact is randomly chosen as your starting bonus
break;
case bartifact:
case PlayerSettings::bartifact:
title = &CGI->generaltexth->allTexts[83]; //{Artifact Bonus}
description = &CGI->generaltexth->allTexts[90]; //An artifact is randomly chosen and equipped to your starting hero
break;
case bgold:
case PlayerSettings::bgold:
title = &CGI->generaltexth->allTexts[84]; //{Gold Bonus}
subTitle = &CGI->generaltexth->allTexts[87]; //500-1000
description = &CGI->generaltexth->allTexts[92]; //At the start of the game, 500-1000 gold is added to your Kingdom's resource pool
break;
case bresource:
case PlayerSettings::bresource:
{
title = &CGI->generaltexth->allTexts[85]; //{Resource Bonus}
switch(CGI->townh->towns[s.castle].primaryRes)
@ -2232,7 +2232,7 @@ CBonusSelection::CBonusSelection( const CCampaign * _ourCampaign, int _whichMap
//bonus choosing
printAtLoc(CGI->generaltexth->allTexts[71], 510, 431, FONT_MEDIUM, zwykly, background); //Choose a bonus:
bonuses = new CHighlightableButtonsGroup(0);
bonuses = new CHighlightableButtonsGroup(bind(&CBonusSelection::selectBonus, this, _1));
//set left part of window
for (int g=0; g<ourCampaign->scenarios.size(); ++g)
@ -2257,19 +2257,14 @@ CBonusSelection::CBonusSelection( const CCampaign * _ourCampaign, int _whichMap
//allies / enemies
printAtLoc(CGI->generaltexth->allTexts[390] + ":", 486, 407, FONT_SMALL, zwykly, background); //Allies
printAtLoc(CGI->generaltexth->allTexts[391] + ":", 619, 407, FONT_SMALL, zwykly, background); //Enemies
int fx=64, ex=244, myT;
myT = ourHeader->players[playerColor].team;
/*for (std::vector<PlayerSettings>::const_iterator i = curOpts->playerInfos.begin(); i != curOpts->playerInfos.end(); i++)
{
int *myx = ((i->color == playerColor || ourHeader.players[i->color].team == myT) ? &fx : &ex);
blitAtLoc(sFlags->ourImages[i->color].bitmap, *myx, 399, to);
*myx += sFlags->ourImages[i->color].bitmap->w;
}*/
SDL_FreeSurface(panel);
//difficulty
printAtLoc("Difficulty", 691, 431, FONT_MEDIUM, zwykly, background); //Difficulty
//load miniflags
sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
}
@ -2278,6 +2273,7 @@ CBonusSelection::~CBonusSelection()
SDL_FreeSurface(background);
delete sizes;
delete ourHeader;
delete sFlags;
}
void CBonusSelection::goBack()
@ -2389,6 +2385,16 @@ void CBonusSelection::show( SDL_Surface * to )
}
blitAtLoc(sizes->ourImages[temp].bitmap, 735, 26, to);
//flags
int fx=530, ex=674, myT;
myT = ourHeader->players[playerColor].team;
for (std::vector<PlayerSettings>::const_iterator i = sInfo.playerInfos.begin(); i != sInfo.playerInfos.end(); i++)
{
int *myx = ((i->color == playerColor || ourHeader->players[i->color].team == myT) ? &fx : &ex);
blitAtLoc(sFlags->ourImages[i->color].bitmap, *myx, 405, to);
*myx += sFlags->ourImages[i->color].bitmap->w;
}
CIntObject::show(to);
}
@ -2397,7 +2403,7 @@ void CBonusSelection::updateBonusSelection()
//graphics:
//spell - SPELLBON.DEF
//monster - TWCRPORT.DEF
//building - ?
//building - BO*.BMP graphics
//artifact - ARTIFBON.DEF
//spell scroll - SPELLBON.DEF
//prim skill - PSKILBON.DEF
@ -2440,13 +2446,17 @@ void CBonusSelection::updateBonusSelection()
break;
case 2: //building
{
static const std::string bldgBitmaps [1][44] = {
{"MAG1", "MAG2", "MAG3", "MAG4", "MAG5", "TAV1", "DOCK", "CAS1", "CAS2", "CAS3",
"HAL1", "HAL2", "HAL3", "HAL4", "MRK1", "MRK2", "BLAK", "LITE", "GR1H", "GR2H",
"ship at the shipyard", "CV1S", "TAV2", "nothing", "nothing", "nothing", "HOLY",
"houses", "houses", "houses", "PIK1", "CRS1", "GR1", "SWD1", "MON1", "CV1", "ANG1",
"PIK2", "CRS2", "GR2", "SWD2", "MON2", "CV2", "ANG2"}
static const std::string bldgBitmaps [1][39] = {
{ //TODO: finish it; HAL1 means "it's a placeholder"
"HAL2", "HAL3", "HAL4", "CAS1", "CAS2", "CAS3", "TAV1", "BLAK", "MRK1", "MRK2", "HAL1",
"MAG1", "MAG2", "MAG3", "MAG4", "MAG5", "DOCK", "HOLY", "LITE", "CV1S", "TAV2", "HAL1"
"PIK1", "CRS1", "GR1", "SWD1", "MON1", "CV1", "ANG1",
"PIK2", "CRS2", "GR2", "SWD2", "MON2", "CV2", "ANG2",
"HAL1", "HAL1", "HAL1", "HAL1"
}
};
static const std::string fracInfixes[F_NUMBER] = {"CS", "R", "T", "I", "N", "D", "s", "F", "E"};
//TODO; find appropriate faction number
@ -2541,9 +2551,11 @@ void CBonusSelection::updateBonusSelection()
break;
case 8: //player
//TODO
continue;
break;
case 9: //hero
//TODO
continue;
break;
}
@ -2585,6 +2597,11 @@ void CBonusSelection::startMap()
::startGame(si);
}
void CBonusSelection::selectBonus( int id )
{
sInfo.choosenCampaignBonus = id;
}
CBonusSelection::CRegion::CRegion( CBonusSelection * _owner, bool _accessible, bool _selectable, int _myNumber )
: owner(_owner), accessible(_accessible), selectable(_selectable), myNumber(_myNumber)
{

View File

@ -323,12 +323,14 @@ class CBonusSelection : public CIntObject
//bonus selection
void updateBonusSelection();
void selectBonus(int id);
CHighlightableButtonsGroup * bonuses;
public:
StartInfo sInfo;
CDefHandler *sFlags;
void selectMap(int whichOne);
void selectBonus(int id);
CBonusSelection(const CCampaign * _ourCampaign, int _whichMap);
~CBonusSelection();

View File

@ -1,8 +1,16 @@
0 30 15 30 15 15 15 30000 0
0 5 2 5 2 2 2 5000 0
1 20 10 20 10 10 10 20000 0
1 10 4 10 4 4 4 7500 0
2 15 7 15 7 7 7 15000 0
2 15 7 15 7 7 7 10000 0
3 10 4 10 4 4 4 10000 0
3 15 7 15 7 7 7 10000 0
4 0 0 0 0 0 0 0 0
4 15 7 15 7 7 7 10000 0
Resources on start. Format:
Difficulty wood mercury ore sulfur crystal gems gold mithril
first line: for human players
second line: for AI players

View File

@ -229,6 +229,7 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const unsigned c
{
CScenarioTravel::STravelBonus bonus;
bonus.type = buffer[outIt++];
//hero: FFFD means 'most powerful' and FFFE means 'generated'
switch(bonus.type)
{
case 0: //spell
@ -460,3 +461,8 @@ bool CCampaignScenario::isNotVoid() const
{
return mapName.size() > 0;
}
bool CScenarioTravel::STravelBonus::isBonusForHero() const
{
return type == 0 || type == 1 || type == 3 || type == 4 || type == 5 || type == 6;
}

View File

@ -50,6 +50,8 @@ public:
//8 - player from previous scenario, 9 - hero [???]
si32 info1, info2, info3; //purpose depends on type
bool isBonusForHero() const;
template <typename Handler> void serialize(Handler &h, const int formatVersion)
{
h & type & info1 & info2 & info3;

View File

@ -31,7 +31,6 @@ bool CGDefInfo::isVisitable() const
CGDefInfo::CGDefInfo()
{
handler = NULL;
serial = -1;
visitDir = (8|16|32|64|128); //4,5,6,7,8 - any not-from-up direction
}
void CDefObjInfoHandler::load()

View File

@ -26,7 +26,6 @@ public:
ui8 coverageMap[6], shadowCoverage[6]; //to determine which tiles are covered by picture of this object
ui8 visitDir; //directions from which object can be entered, format same as for moveDir in CGHeroInstance(but 0 - 7)
si32 id, subid; //of object described by this defInfo
si32 serial;
si32 terrainAllowed, //on which terrain it is possible to place object
terrainMenu; //in which menus in map editor object will be showed
si32 width, height; //tiles
@ -43,7 +42,7 @@ public:
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & name & serial & visitMap & blockMap & visitDir & id & subid &terrainAllowed
h & name & visitMap & blockMap & visitDir & id & subid &terrainAllowed
& terrainMenu & width & height & type & printPriority & coverageMap & shadowCoverage;
}
CGDefInfo();

View File

@ -656,6 +656,36 @@ ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
return secSkills[i].second;
return 0;
}
void CGHeroInstance::setSecSkillLevel(int which, int val, bool abs)
{
if(getSecSkillLevel(which) == 0)
{
secSkills.push_back(std::pair<int,int>(which, val));
updateSkill(which, val);
}
else
{
for (unsigned i=0; i<secSkills.size(); i++)
{
if(secSkills[i].first == which)
{
if(abs)
secSkills[i].second = val;
else
secSkills[i].second += val;
if(secSkills[i].second > 3) //workaround to avoid crashes when same sec skill is given more than once
{
tlog1 << "Warning: Skill " << which << " increased over limit! Decreasing to Expert.\n";
secSkills[i].second = 3;
}
updateSkill(which, secSkills[i].second); //when we know final value
}
}
}
}
int CGHeroInstance::maxMovePoints(bool onLand) const
{
int base = -1;

View File

@ -355,6 +355,8 @@ public:
TModDescr getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above
int getPrimSkillLevel(int id) const; //0-attack, 1-defence, 2-spell power, 3-knowledge
ui8 getSecSkillLevel(const int & ID) const; //0 - no skill
void setSecSkillLevel(int which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value
int maxMovePoints(bool onLand) const;
ui32 getArtAtPos(ui16 pos) const; //-1 - no artifact

View File

@ -1189,8 +1189,67 @@ CGameState::~CGameState()
delete applierGs;
delete objCaller;
}
void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
{
struct HLP
{
//heroType: FFFD means 'most powerful' and FFFE means 'generated'
static void giveCampaignBonusToHero(CGHeroInstance * hero, si32 heroType, const StartInfo * si, const CScenarioTravel & st )
{
const CScenarioTravel::STravelBonus & curBonus = st.bonusesToChoose[si->choosenCampaignBonus];
if(curBonus.isBonusForHero() && curBonus.info1 == heroType)
{
//apply bonus
switch (curBonus.type)
{
case 0: //spell
hero->spells.insert(curBonus.info2);
break;
case 1: //monster
//TODO
break;
case 3: //artifact
hero->giveArtifact(curBonus.info2);
break;
case 4: //spell scroll
//TODO
break;
case 5: //prim skill
{
const ui8* ptr = reinterpret_cast<const ui8*>(curBonus.info2);
for (int g=0; g<PRIMARY_SKILLS; ++g)
{
int val = ptr[g];
if (val == 0)
{
continue;
}
Bonus bb(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, si->whichMapInCampaign, g);
hero->bonuses.push_back(bb);
}
}
break;
case 6: //sec skills
hero->setSecSkillLevel(curBonus.info2, curBonus.info3, true);
break;
}
}
}
static std::vector<const PlayerSettings *> getHumanPlayerInfo(const StartInfo * si)
{
std::vector<const PlayerSettings *> ret;
for (int g=0; g<si->playerInfos.size(); ++g)
{
if(si->playerInfos[g].human)
ret.push_back(&si->playerInfos[g]);
}
return ret;
}
};
VLC->arth->allowedArtifacts.clear();
VLC->arth->clearHlpLists();
switch(si->mode)
@ -1345,6 +1404,11 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
map->heroes.push_back(nnn);
map->objects.push_back(nnn);
map->addBlockVisTiles(nnn);
//give campaign bonus
if (si->mode == 2 && getPlayer(nnn->tempOwner)->human)
{
HLP::giveCampaignBonusToHero(nnn, 0xFFFE, si, campaign->camp->scenarios[si->whichMapInCampaign].travelOptions);
}
}
}
@ -1358,21 +1422,26 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
players.insert(ins);
}
/******************RESOURCES****************************************************/
//TODO: computer player should receive other amount of resource than player (depending on difficulty)
std::vector<int> startres;
std::vector<int> startresAI, startresHuman;
std::ifstream tis(DATA_DIR "/config/startres.txt");
int k;
for (int j=0;j<scenarioOps->difficulty;j++)
for (int j=0; j<scenarioOps->difficulty * 2; j++)
{
tis >> k;
for (int z=0;z<RESOURCE_QUANTITY;z++)
tis>>k;
}
tis >> k;
for (int i=0;i<RESOURCE_QUANTITY;i++)
for (int i=0; i<RESOURCE_QUANTITY; i++)
{
tis >> k;
startres.push_back(k);
startresHuman.push_back(k);
}
tis >> k;
for (int i=0; i<RESOURCE_QUANTITY; i++)
{
tis >> k;
startresAI.push_back(k);
}
tis.close();
tis.clear();
@ -1380,7 +1449,51 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
{
(*i).second.resources.resize(RESOURCE_QUANTITY);
for (int x=0;x<RESOURCE_QUANTITY;x++)
(*i).second.resources[x] = startres[x];
{
if (i->second.human)
{
(*i).second.resources[x] = startresHuman[x];
}
else
{
(*i).second.resources[x] = startresAI[x];
}
}
}
//give start resource bonus in case of campaign
if (si->mode == 2)
{
CScenarioTravel::STravelBonus chosenBonus =
campaign->camp->scenarios[si->whichMapInCampaign].travelOptions.bonusesToChoose[si->choosenCampaignBonus];
if(chosenBonus.type == 7) //resource
{
std::vector<const PlayerSettings *> people = HLP::getHumanPlayerInfo(si); //players we will give resource bonus
for (int b=0; b<people.size(); ++b)
{
std::vector<int> res; //resources we will give
switch (chosenBonus.info1)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6:
res.push_back(chosenBonus.info1);
break;
case 0xFD: //wood+ore
res.push_back(0); res.push_back(2);
break;
case 0xFE: //rare
res.push_back(1); res.push_back(3); res.push_back(4); res.push_back(5);
break;
default:
assert(0);
break;
}
//increasing resource quantity
for (int n=0; n<res.size(); ++n)
{
players[people[b]->color].resources[res[n]] += chosenBonus.info2;
}
}
}
}
@ -1462,14 +1575,14 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
}
//starting bonus
if(si->playerInfos[k->second.serial].bonus==brandom)
if(si->playerInfos[k->second.serial].bonus==PlayerSettings::brandom)
si->playerInfos[k->second.serial].bonus = ran()%3;
switch(si->playerInfos[k->second.serial].bonus)
{
case bgold:
case PlayerSettings::bgold:
k->second.resources[6] += 500 + (ran()%6)*100;
break;
case bresource:
case PlayerSettings::bresource:
{
int res = VLC->townh->towns[si->playerInfos[k->second.serial].castle].primaryRes;
if(res == 127)
@ -1483,7 +1596,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
}
break;
}
case bartifact:
case PlayerSettings::bartifact:
{
if(!k->second.heroes.size())
{
@ -1611,11 +1724,6 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
}
}
for(unsigned int i=0; i<map->defy.size(); i++)
{
map->defy[i]->serial = i;
}
objCaller->preInit();
for(unsigned int i=0; i<map->objects.size(); i++)
{
@ -1626,11 +1734,6 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
objCaller->postInit();
}
bool CGameState::battleShootCreatureStack(int ID, int dest)
{
return true;
}
bool CGameState::battleCanFlee(int player)
{
if(!curB) //there is no battle

View File

@ -413,9 +413,6 @@ public:
CGTownInstance *getTown(int objid);
const CGHeroInstance *getHero(int objid) const;
const CGTownInstance *getTown(int objid) const;
bool battleMoveCreatureStack(int ID, int dest);
bool battleAttackCreatureStack(int ID, int dest);
bool battleShootCreatureStack(int ID, int dest);
bool battleCanFlee(int player); //returns true if player can flee from the battle
int battleGetStack(int pos, bool onlyAlive); //returns ID of stack at given tile
int battleGetBattlefieldType(int3 tile = int3());// 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship

View File

@ -191,7 +191,8 @@ struct DLL_EXPORT Bonus
HERO_BASE_SKILL,
SECONDARY_SKILL,
HERO_SPECIAL,
ARMY
ARMY,
CAMPAIGN_BONUS
};
enum LimitEffect

View File

@ -77,31 +77,7 @@ DLL_EXPORT void SetPrimSkill::applyGs( CGameState *gs )
DLL_EXPORT void SetSecSkill::applyGs( CGameState *gs )
{
CGHeroInstance *hero = gs->getHero(id);
if(hero->getSecSkillLevel(which) == 0)
{
hero->secSkills.push_back(std::pair<int,int>(which, val));
hero->updateSkill(which, val);
}
else
{
for (unsigned i=0; i<hero->secSkills.size(); i++)
{
if(hero->secSkills[i].first == which)
{
if(abs)
hero->secSkills[i].second = val;
else
hero->secSkills[i].second += val;
if(hero->secSkills[i].second > 3) //workaround to avoid crashes when same sec skill is given more than once
{
tlog1 << "Warning: Skill " << which << " increased over limit! Decreasing to Expert.\n";
hero->secSkills[i].second = 3;
}
hero->updateSkill(which, hero->secSkills[i].second); //when we know final value
}
}
}
hero->setSecSkillLevel(which, val, abs);
}
DLL_EXPORT void HeroVisitCastle::applyGs( CGameState *gs )