diff --git a/CGameState.cpp b/CGameState.cpp index 02debc674..1602ab1c3 100644 --- a/CGameState.cpp +++ b/CGameState.cpp @@ -56,13 +56,18 @@ CGObjectInstance * createObject(int id, int subid, int3 pos, int owner) nobj->defInfo->blockMap[5] = 253; nobj->defInfo->visitMap[5] = 2; nobj->artifWorn[16] = 3; + if(nobj->type->heroType % 2 == 1) //it's a magical hero + { + nobj->artifWorn[17] = 0; //give him spellbook + } nobj->portrait = subid; nobj->primSkills.resize(4); nobj->primSkills[0] = nobj->type->heroClass->initialAttack; nobj->primSkills[1] = nobj->type->heroClass->initialDefence; nobj->primSkills[2] = nobj->type->heroClass->initialPower; nobj->primSkills[3] = nobj->type->heroClass->initialKnowledge; - nobj->mana = 10 * nobj->primSkills[3]; + nobj->secSkills = nobj->type->secSkillsInit; //copying initial secondary skills + nobj->mana = 10 * nobj->getPrimSkillLevel(3); return nobj; } case 98: //town @@ -1000,7 +1005,10 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed) vhi->exp=40+ran()%50; vhi->level = 1; } - if (vhi->level>1) ;//TODO dodac um dr, ale potrzebne los + if(vhi->secSkills.size() == 1 && vhi->secSkills[0] == std::make_pair(-1, -1)) //set secondary skills to default + { + vhi->secSkills = vhi->type->secSkillsInit; + } if ((!vhi->primSkills.size()) || (vhi->primSkills[0]<0)) { if (vhi->primSkills.size()primSkills[2] = vhi->type->heroClass->initialPower; vhi->primSkills[3] = vhi->type->heroClass->initialKnowledge; } - vhi->mana = vhi->primSkills[3]*10; + vhi->mana = vhi->getPrimSkillLevel(3)*10; if (!vhi->name.length()) { vhi->name = vhi->type->name; @@ -1023,6 +1031,10 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed) vhi->portrait = vhi->type->ID; vhi->artifWorn[16] = 3; + if(vhi->type->heroType % 2 == 1) //it's a magical hero + { + vhi->artifWorn[17] = 0; //give him spellbook + } //initial army if (!vhi->army.slots.size()) //standard army @@ -1050,6 +1062,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed) vhi->army.slots[x-pom2].second = (ran()%pom)+vhi->type->lowStack[x]; else vhi->army.slots[x-pom2].second = +vhi->type->lowStack[x]; + vhi->army.formation = false; } } @@ -1347,9 +1360,9 @@ std::set CGameState::tilesToReveal(int3 pos, int radious, int player) return ret; } -int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender) +int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting) { - int attackDefenseBonus = attacker->creature->attack - defender->creature->defence; + int attackDefenseBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0) - (defender->creature->defence + (defendingHero ? defendingHero->getPrimSkillLevel(1) : 0)); int damageBase = 0; if(attacker->creature->damageMax == attacker->creature->damageMin) //constant damage { @@ -1360,7 +1373,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender) damageBase = rand()%(attacker->creature->damageMax - attacker->creature->damageMin) + attacker->creature->damageMin + 1; } - float dmgBonusMultiplier = 1.0; + float dmgBonusMultiplier = 1.0f; if(attackDefenseBonus < 0) //decreasing dmg { if(0.02f * (-attackDefenseBonus) > 0.3f) @@ -1383,6 +1396,55 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender) dmgBonusMultiplier += 0.05f * attackDefenseBonus; } } + //handling secondary abilities + if(attackerHero) + { + if(shooting) + { + switch(attackerHero->getSecSkillLevel(1)) //archery + { + case 1: //basic + dmgBonusMultiplier *= 1.1f; + break; + case 2: //advanced + dmgBonusMultiplier *= 1.25f; + break; + case 3: //expert + dmgBonusMultiplier *= 1.5f; + break; + } + } + else + { + switch(attackerHero->getSecSkillLevel(22)) //offence + { + case 1: //basic + dmgBonusMultiplier *= 1.1f; + break; + case 2: //advanced + dmgBonusMultiplier *= 1.2f; + break; + case 3: //expert + dmgBonusMultiplier *= 1.3f; + break; + } + } + } + if(defendingHero) + { + switch(defendingHero->getSecSkillLevel(23)) //armourer + { + case 1: //basic + dmgBonusMultiplier *= 0.95f; + break; + case 2: //advanced + dmgBonusMultiplier *= 0.9f; + break; + case 3: //expert + dmgBonusMultiplier *= 0.85f; + break; + } + } return (float)damageBase * (float)attacker->amount * dmgBonusMultiplier; } diff --git a/CGameState.h b/CGameState.h index 6a8c6ef0f..1a69e6b11 100644 --- a/CGameState.h +++ b/CGameState.h @@ -73,7 +73,7 @@ struct DLL_EXPORT BattleInfo static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left) static std::vector neighbouringTiles(int hex); - static int calculateDmg(const CStack* attacker, const CStack* defender); //TODO: add additional conditions and require necessary data + static int calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting); //TODO: add additional conditions and require necessary data void calculateCasualties(std::set > *casualties); }; diff --git a/CHeroWindow.cpp b/CHeroWindow.cpp index 75b46cb14..68a269149 100644 --- a/CHeroWindow.cpp +++ b/CHeroWindow.cpp @@ -220,7 +220,7 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero) for(int g=0; gbonus = hero->primSkills[g]; + primSkillAreas[g]->bonus = hero->getPrimSkillLevel(g); } for(int g=0; gsecSkills.size(); ++g) { @@ -236,7 +236,7 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero) sprintf(bufor, CGI->generaltexth->allTexts[2].substr(1, CGI->generaltexth->allTexts[2].size()-2).c_str(), hero->level, CGI->heroh->reqExp(hero->level+1), hero->exp); expArea->text = std::string(bufor); - sprintf(bufor, CGI->generaltexth->allTexts[205].substr(1, CGI->generaltexth->allTexts[205].size()-2).c_str(), hero->name.c_str(), hero->mana, hero->primSkills[3]*10); + sprintf(bufor, CGI->generaltexth->allTexts[205].substr(1, CGI->generaltexth->allTexts[205].size()-2).c_str(), hero->name.c_str(), hero->mana, hero->getPrimSkillLevel(3)*10); spellPointsArea->text = std::string(bufor); for(int g=0; gprimSkills[0]; + primarySkill1<getPrimSkillLevel(0); CSDL_Ext::printAtMiddle(primarySkill1.str(), 53, 165, TNRB16, zwykly, curBack); std::stringstream primarySkill2; - primarySkill2<primSkills[1]; + primarySkill2<getPrimSkillLevel(1); CSDL_Ext::printAtMiddle(primarySkill2.str(), 123, 165, TNRB16, zwykly, curBack); std::stringstream primarySkill3; - primarySkill3<primSkills[2]; + primarySkill3<getPrimSkillLevel(2); CSDL_Ext::printAtMiddle(primarySkill3.str(), 193, 165, TNRB16, zwykly, curBack); std::stringstream primarySkill4; - primarySkill4<primSkills[3]; + primarySkill4<getPrimSkillLevel(3); CSDL_Ext::printAtMiddle(primarySkill4.str(), 263, 165, TNRB16, zwykly, curBack); blitAt(graphics->luck42->ourImages[curHero->getCurrentLuck()+3].bitmap, 239, 182, curBack); @@ -650,7 +650,7 @@ void CHeroWindow::redrawCurBack() CSDL_Ext::printAt(expstr.str(), 69, 247, GEOR16, zwykly, curBack); CSDL_Ext::printAt(CGI->generaltexth->jktexts[7].substr(1, CGI->generaltexth->jktexts[7].size()-2), 212, 231, GEOR13, tytulowy, curBack); std::stringstream manastr; - manastr<mana<<'/'<primSkills[3]*10; + manastr<mana<<'/'<getPrimSkillLevel(3)*10; CSDL_Ext::printAt(manastr.str(), 212, 247, GEOR16, zwykly, curBack); } diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index a8e00ae29..d4436d050 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -134,8 +134,8 @@ void CGarrisonSlot::clickRight (tribool down) pom = new StackState(); const CGHeroInstance *h = static_cast(getObj()); pom->currentHealth = 0; - pom->attackBonus = h->primSkills[0]; - pom->defenseBonus = h->primSkills[1]; + pom->attackBonus = h->getPrimSkillLevel(0); + pom->defenseBonus = h->getPrimSkillLevel(1); pom->luck = h->getCurrentLuck(); pom->morale = h->getCurrentMorale(); } diff --git a/client/Graphics.cpp b/client/Graphics.cpp index 8ecca3e21..244ee12ea 100644 --- a/client/Graphics.cpp +++ b/client/Graphics.cpp @@ -27,7 +27,7 @@ SDL_Surface * Graphics::drawPrimarySkill(const CGHeroInstance *curh, SDL_Surface char * buf = new char[10]; for (int i=from;iprimSkills[i],buf,10); + SDL_itoa(curh->getPrimSkillLevel(i),buf,10); printAtMiddle(buf,84+28*i,68,GEOR13,zwykly,ret); } delete[] buf; diff --git a/config/heroes_sec_skills.txt b/config/heroes_sec_skills.txt new file mode 100644 index 000000000..86e7d31c6 --- /dev/null +++ b/config/heroes_sec_skills.txt @@ -0,0 +1,158 @@ +//heroes'_inintial_set_of_secondary_abilities_format:_heroID_numberOfInitialSecSkills_(Skill_ID,_skill_lvl_for_every_spell) +0 2 6 1 1 1 +1 2 6 1 1 1 +2 2 6 1 23 1 +3 2 6 1 5 1 +4 2 6 1 13 1 +5 2 6 1 22 1 +6 2 6 1 19 1 +7 2 6 1 19 1 +8 2 7 1 27 1 +9 2 7 1 4 1 +10 2 7 1 13 1 +11 1 7 2 +12 2 7 1 8 1 +13 2 7 1 11 1 +14 2 7 1 21 1 +15 2 7 1 24 1 +16 2 6 1 23 1 +17 2 9 1 26 1 +18 1 1 2 +19 2 4 1 6 1 +20 1 26 2 +21 2 1 1 22 1 +22 2 0 1 26 1 +23 2 1 1 2 1 +24 2 7 1 18 1 +25 2 7 2 10 1 +26 2 7 1 24 1 +27 2 7 1 27 1 +28 2 7 1 11 1 +29 2 7 1 9 1 +30 2 7 1 25 1 +31 2 7 1 3 1 +32 2 3 1 8 1 +33 1 18 2 +34 2 8 1 25 1 +35 2 18 1 23 1 +36 2 8 1 19 1 +37 2 18 1 26 1 +38 2 8 1 22 1 +39 2 18 1 24 1 +40 1 7 2 +41 2 7 1 8 1 +42 2 7 1 11 1 +43 2 7 1 24 1 +44 2 7 1 10 1 +45 2 7 1 25 1 +46 2 7 1 4 1 +47 2 7 1 18 1 +48 1 3 2 +49 2 7 1 18 1 +50 1 23 2 +51 2 19 1 26 1 +52 2 18 1 22 1 +53 2 1 1 3 1 +54 2 1 1 2 1 +55 1 22 2 +56 2 7 1 24 1 +57 2 7 1 18 1 +58 2 7 1 8 1 +59 2 7 1 10 1 +60 2 7 1 21 1 +61 2 7 1 11 1 +62 2 7 1 25 1 +63 2 7 1 6 1 +64 2 12 1 26 1 +65 2 12 1 20 1 +66 2 12 1 21 1 +67 2 12 1 19 1 +68 2 12 1 22 1 +69 1 12 2 +70 2 12 1 22 1 +71 2 12 1 23 1 +72 2 12 1 18 1 +73 2 12 1 7 1 +74 2 12 1 25 1 +75 2 12 1 11 1 +76 2 12 1 8 1 +77 2 12 1 21 1 +78 1 12 2 +79 2 12 1 24 1 +80 2 3 1 6 1 +81 2 20 1 22 1 +82 2 19 1 22 1 +83 2 6 1 26 1 +84 1 22 2 +85 2 2 1 19 1 +86 2 6 1 18 1 +87 2 19 1 22 1 +88 2 7 1 18 1 +89 2 7 1 8 1 +90 2 7 1 25 1 +91 1 7 2 +92 2 7 1 11 1 +93 2 7 1 3 2 +94 2 7 1 24 1 +95 2 7 1 21 1 +96 2 22 1 10 1 +97 2 22 1 20 1 +98 2 22 1 1 1 +99 2 22 1 3 1 +100 2 22 1 0 1 +101 2 22 1 26 1 +102 1 22 2 +103 2 22 1 19 1 +104 2 7 1 25 1 +105 2 7 1 6 1 +106 2 7 1 2 1 +107 2 7 1 19 1 +108 2 7 1 20 1 +109 2 7 1 22 1 +110 2 7 1 11 1 +111 2 7 1 26 1 +112 2 23 1 26 1 +113 2 23 1 6 1 +114 2 23 1 1 1 +115 1 23 2 +116 2 23 1 22 1 +117 2 23 1 0 1 +118 2 23 1 20 1 +119 2 23 1 3 1 +120 1 7 2 +121 2 7 1 8 1 +122 2 7 1 5 1 +123 2 7 1 27 1 +124 2 7 1 21 1 +125 2 7 1 25 1 +126 2 7 1 24 1 +127 2 7 1 11 1 +128 2 20 1 22 1 +129 2 13 1 19 1 +130 2 20 1 22 1 +131 1 19 2 +132 2 2 1 22 1 +133 2 13 1 19 1 +134 1 22 2 +135 2 19 1 21 1 +136 2 7 1 14 1 +137 2 7 1 15 1 +138 2 7 1 16 1 +139 2 7 1 17 1 +140 2 7 1 14 1 +141 2 7 1 15 1 +142 2 7 1 16 1 +143 2 7 1 17 1 +144 1 6 2 +145 2 7 1 14 3 +146 2 6 1 22 1 +147 1 7 2 +148 2 1 1 6 1 +149 1 22 2 +150 1 12 2 +151 2 13 1 19 1 +152 2 6 1 23 1 +153 2 13 1 19 1 +154 2 19 1 22 1 +155 2 6 1 19 1 +-1 \ No newline at end of file diff --git a/hch/CHeroHandler.cpp b/hch/CHeroHandler.cpp index 8602c4747..233137b5b 100644 --- a/hch/CHeroHandler.cpp +++ b/hch/CHeroHandler.cpp @@ -14,17 +14,17 @@ CHeroClass::CHeroClass() CHeroClass::~CHeroClass() { } -int CHeroClass::chooseSecSkill(std::set possibles) //picks secondary skill out from given possibilities +int CHeroClass::chooseSecSkill(const std::set & possibles) const //picks secondary skill out from given possibilities { if(possibles.size()==1) return *possibles.begin(); int totalProb = 0; - for(std::set::iterator i=possibles.begin(); i!=possibles.end(); i++) + for(std::set::const_iterator i=possibles.begin(); i!=possibles.end(); i++) { totalProb += proSec[*i]; } int ran = rand()%totalProb; - for(std::set::iterator i=possibles.begin(); i!=possibles.end(); i++) + for(std::set::const_iterator i=possibles.begin(); i!=possibles.end(); i++) { ran -= proSec[*i]; if(ran<0) @@ -111,6 +111,35 @@ void CHeroHandler::loadHeroes() nher->ID = heroes.size(); heroes.push_back(nher); } + //loading initial secondary skills + std::ifstream inp; + inp.open("config" PATHSEPARATOR "heroes_sec_skills.txt", std::ios_base::in|std::ios_base::binary); + if(!inp.is_open()) + { + tlog1<<"missing file: config/heroes_sec_skills.txt"<>dump; + int hid; //ID of currently read hero + int secQ; //number of secondary abilities + while(true) + { + inp>>hid; + if(hid == -1) + break; + inp>>secQ; + for(int g=0; g>a; inp>>b; + heroes[hid]->secSkillsInit.push_back(std::make_pair(a, b)); + } + } + inp.close(); + } + //initial skills loaded + loadSpecialAbilities(); loadBiographies(); loadHeroClasses(); diff --git a/hch/CHeroHandler.h b/hch/CHeroHandler.h index 34bf77c8c..77f6b2e84 100644 --- a/hch/CHeroHandler.h +++ b/hch/CHeroHandler.h @@ -20,6 +20,7 @@ public: bool isAllowed; //true if we can play with this hero (depends on map) CHeroClass * heroClass; EHeroClasses heroType; //hero class + std::vector > secSkillsInit; //initial secondaryskills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert) //bool operator<(CHero& drugi){if (ID < drugi.ID) return true; else return false;} }; @@ -35,7 +36,7 @@ public: int selectionProbability[9]; //probability of selection in towns std::vector terrCosts; //default costs of going through terrains: dirt, sand, grass, snow, swamp, rough, subterrain, lava, water, rock; -1 means terrain is imapassable CDefHandler * moveAnim; //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing - int chooseSecSkill(std::set possibles); //picks secondary skill out from given possibilities + int chooseSecSkill(const std::set & possibles) const; //picks secondary skill out from given possibilities CHeroClass(); ~CHeroClass(); }; diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index e58790243..b37523ac9 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -275,6 +275,10 @@ int CGHeroInstance::getCurrentMorale() const //TODO: write it return 0; } +int CGHeroInstance::getPrimSkillLevel(int id) const +{ + return primSkills[id]; +} int CGHeroInstance::getSecSkillLevel(const int & ID) const { for(int i=0;i primSkills; //0-attack, 1-defence, 2-spell power, 3-knowledge - std::vector > secSkills; //first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert) + std::vector > secSkills; //first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert); if hero has ability (-1, -1) it meansthat it should have default secondary abilities int movement; //remaining movement points int identifier; //from the map file bool sex; @@ -125,6 +125,7 @@ public: bool canWalkOnSea() const; int getCurrentLuck() const; int getCurrentMorale() const; + int getPrimSkillLevel(int id) const; int getSecSkillLevel(const int & ID) const; //0 - no skill ui32 getArtAtPos(ui16 pos) const; //-1 - no artifact void setArtAtPos(ui16 pos, int art); diff --git a/map.cpp b/map.cpp index 452c2a104..71c0d9861 100644 --- a/map.cpp +++ b/map.cpp @@ -1052,6 +1052,10 @@ void Mapa::loadHero( CGObjectInstance * &nobj, unsigned char * bufor, int &i ) nhi->secSkills[yy].second = readNormalNr(bufor,i, 1); ++i; } } + else //set default secondary skils + { + nhi->secSkills.push_back(std::make_pair(-1, -1)); + } if(readChar(bufor,i))//true if hero has nonstandard garrison nhi->army = readCreatureSet(bufor,i,7,(version>RoE)); nhi->army.formation =bufor[i]; ++i; //formation diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 55796d48b..643119719 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -349,11 +349,11 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile delete battleResult.data; } -void prepareAttack(BattleAttack &bat, CStack *att, CStack *def) +void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def, bool shooting) { bat.stackAttacking = att->ID; bat.bsa.stackAttacked = def->ID; - bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def);//counting dealt damage + bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), shooting);//counting dealt damage //applying damages bat.bsa.killedAmount = bat.bsa.damageAmount / def->creature->hitPoints; @@ -948,14 +948,14 @@ upgend: return; BattleAttack bat; - prepareAttack(bat,curStack,stackAtEnd); + prepareAttack(bat,curStack,stackAtEnd,false); sendAndApply(&bat); //counterattack if(!vstd::contains(curStack->abilities,NO_ENEMY_RETALIATION) && stackAtEnd->alive() && stackAtEnd->counterAttacks ) //TODO: support for multiple retaliatons per turn { - prepareAttack(bat,stackAtEnd,curStack); + prepareAttack(bat,stackAtEnd,curStack,false); bat.flags |= 2; sendAndApply(&bat); } @@ -965,7 +965,7 @@ upgend: && stackAtEnd->alive() ) { bat.flags = 0; - prepareAttack(bat,curStack,stackAtEnd); + prepareAttack(bat,curStack,stackAtEnd,false); sendAndApply(&bat); } sendDataToClients(ui16(3008)); //end movement and attack @@ -981,13 +981,13 @@ upgend: *destStack= gs->curB->getStackT(ba.destinationTile); BattleAttack bat; - prepareAttack(bat,curStack,destStack); + prepareAttack(bat,curStack,destStack,true); bat.flags |= 1; if(vstd::contains(curStack->abilities,TWICE_ATTACK) && curStack->alive()) { - prepareAttack(bat,curStack,destStack); + prepareAttack(bat,curStack,destStack,true); sendAndApply(&bat); } diff --git a/server/CGameHandler.h b/server/CGameHandler.h index edc4772ae..f9e041188 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -12,6 +12,7 @@ struct StartInfo; class CCPPObjectScript; class CScriptCallback; struct BattleResult; +struct BattleAttack; template struct CPack; template struct Query; class CGHeroInstance; @@ -56,6 +57,7 @@ class CGameHandler void giveSpells(const CGTownInstance *t, const CGHeroInstance *h); void moveStack(int stack, int dest); void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::function cb); //use hero=NULL for no hero + void prepareAttack(BattleAttack &bat, CStack *att, CStack *def, bool shooting); //if last parameter is true, attack is by shooting, if false it's a melee attack void checkForBattleEnd( std::vector &stacks ); void setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army1, CCreatureSet &army2, CGHeroInstance * hero1, CGHeroInstance * hero2 );