diff --git a/StartInfo.h b/StartInfo.h index 0639e2c67..0cadb385d 100644 --- a/StartInfo.h +++ b/StartInfo.h @@ -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; isecSkills.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; diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 3aaa577d7..5e3ea289b 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -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; gscenarios.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::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::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) { diff --git a/client/CPreGame.h b/client/CPreGame.h index 7411ead34..c3cb336a7 100644 --- a/client/CPreGame.h +++ b/client/CPreGame.h @@ -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(); diff --git a/config/startres.txt b/config/startres.txt index 518acc6c6..455ea488d 100644 --- a/config/startres.txt +++ b/config/startres.txt @@ -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 diff --git a/hch/CCampaignHandler.cpp b/hch/CCampaignHandler.cpp index 05a2bac95..c5381923b 100644 --- a/hch/CCampaignHandler.cpp +++ b/hch/CCampaignHandler.cpp @@ -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; +} diff --git a/hch/CCampaignHandler.h b/hch/CCampaignHandler.h index c9be3328c..a720b52c6 100644 --- a/hch/CCampaignHandler.h +++ b/hch/CCampaignHandler.h @@ -50,6 +50,8 @@ public: //8 - player from previous scenario, 9 - hero [???] si32 info1, info2, info3; //purpose depends on type + bool isBonusForHero() const; + template void serialize(Handler &h, const int formatVersion) { h & type & info1 & info2 & info3; diff --git a/hch/CDefObjInfoHandler.cpp b/hch/CDefObjInfoHandler.cpp index d84284b32..0c0e02d6a 100644 --- a/hch/CDefObjInfoHandler.cpp +++ b/hch/CDefObjInfoHandler.cpp @@ -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() diff --git a/hch/CDefObjInfoHandler.h b/hch/CDefObjInfoHandler.h index 789d7b225..69f46b356 100644 --- a/hch/CDefObjInfoHandler.h +++ b/hch/CDefObjInfoHandler.h @@ -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 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(); diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index 102e5966f..44c8ddfcc 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -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(which, val)); + updateSkill(which, val); + } + else + { + for (unsigned i=0; i 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; diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index dadf07032..f1452437e 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -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 diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 2f6f79170..22c63b92f 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -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(curBonus.info2); + for (int g=0; gwhichMapInCampaign, g); + hero->bonuses.push_back(bb); + } + } + break; + case 6: //sec skills + hero->setSecSkillLevel(curBonus.info2, curBonus.info3, true); + break; + } + } + } + + static std::vector getHumanPlayerInfo(const StartInfo * si) + { + std::vector ret; + for (int g=0; gplayerInfos.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 startres; + std::vector startresAI, startresHuman; std::ifstream tis(DATA_DIR "/config/startres.txt"); int k; - for (int j=0;jdifficulty;j++) + for (int j=0; jdifficulty * 2; j++) { tis >> k; for (int z=0;z>k; } tis >> k; - for (int i=0;i> k; - startres.push_back(k); + startresHuman.push_back(k); + } + tis >> k; + for (int i=0; i> 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;xsecond.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 people = HLP::getHumanPlayerInfo(si); //players we will give resource bonus + for (int b=0; b 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; ncolor].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; idefy.size(); i++) - { - map->defy[i]->serial = i; - } - objCaller->preInit(); for(unsigned int i=0; iobjects.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 diff --git a/lib/CGameState.h b/lib/CGameState.h index f03e28ef2..b9687e1fe 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -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 diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index b0897d990..717f4d79c 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -191,7 +191,8 @@ struct DLL_EXPORT Bonus HERO_BASE_SKILL, SECONDARY_SKILL, HERO_SPECIAL, - ARMY + ARMY, + CAMPAIGN_BONUS }; enum LimitEffect diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 67d97d807..5d6608cea 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -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(which, val)); - hero->updateSkill(which, val); - } - else - { - for (unsigned i=0; isecSkills.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 )