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

* added shots limit

* improved hero hiring
* tree of knowledge will give right number of exp points
* fixed bug with double showing "getting hit" animation
* more logs in initialization of creature handler
* added 'vcmiglorfindel' cheat (works as woggandalfwhite)
* minor improvements
This commit is contained in:
Michał W. Urbańczyk 2008-10-31 22:41:22 +00:00
parent ee54e5d2e2
commit 248b5e8677
12 changed files with 153 additions and 63 deletions

View File

@ -1819,6 +1819,7 @@ void CBattleHex::clickRight(boost::logic::tribool down)
pom->defenseBonus = h->primSkills[1];
pom->luck = h->getCurrentLuck();
pom->morale = h->getCurrentMorale();
pom->shotsLeft = myst.shots;
}
pom->currentHealth = myst.firstHPleft;
(new CCreInfoWindow(myst.creature->idNumber,0,myst.amount,pom,boost::function<void()>(),boost::function<void()>(),NULL))

View File

@ -523,7 +523,7 @@ bool CCallback::battleIsStackMine(int ID)
}
return false;
}
bool CCallback::battleCanShoot(int ID, int dest) //TODO: check arrows amount
bool CCallback::battleCanShoot(int ID, int dest)
{
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
CStack *our=battleGetStackByID(ID), *dst=battleGetStackByPos(dest);
@ -532,6 +532,7 @@ bool CCallback::battleCanShoot(int ID, int dest) //TODO: check arrows amount
&& our->owner != dst->owner
&& dst->alive()
&& !gs->curB->isStackBlocked(ID)
&& our->shots
)
return true;
return false;

View File

@ -247,6 +247,62 @@ CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S)
abilities = C->abilities;
state.insert(ALIVE);
}
CGHeroInstance* CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, int notThatOne)
{
if(player<0 || player>=PLAYER_LIMIT)
{
tlog1 << "Cannot pick hero for " << town->name << ". Wrong owner!\n";
return NULL;
}
std::vector<CGHeroInstance *> pool;
int sum=0, r;
if(native)
{
for(std::map<ui32,CGHeroInstance *>::iterator i=heroesPool.begin(); i!=heroesPool.end(); i++)
{
if(pavailable[i->first] & 1<<player
&& i->second->type->heroType/2 == town->typeID
&& i->second->subID != notThatOne
)
{
pool.push_back(i->second);
}
}
if(!pool.size())
return pickHeroFor(false,player,town,notThatOne);
else
return pool[rand()%pool.size()];
}
else
{
for(std::map<ui32,CGHeroInstance *>::iterator i=heroesPool.begin(); i!=heroesPool.end(); i++)
{
if(pavailable[i->first] & 1<<player
&& i->second->subID != notThatOne
)
{
pool.push_back(i->second);
sum += i->second->type->heroClass->selectionProbability[town->typeID];
}
}
if(!pool.size())
{
tlog1 << "There are no heroes available for player " << player<<"!\n";
return NULL;
}
r = rand()%sum;
for(int i=0; i<pool.size(); i++)
{
r -= pool[i]->type->heroClass->selectionProbability[town->typeID];
if(r<0)
return pool[i];
}
return pool[pool.size()-1];
}
}
void CGameState::applyNL(IPack * pack)
{
switch(pack->getType())
@ -401,6 +457,16 @@ void CGameState::applyNL(IPack * pack)
players[rh->player].availableHeroes.clear();
players[rh->player].availableHeroes.push_back(hpool.heroesPool[rh->hid1]);
players[rh->player].availableHeroes.push_back(hpool.heroesPool[rh->hid2]);
if(rh->flags & 1)
{
hpool.heroesPool[rh->hid1]->army.slots.clear();
hpool.heroesPool[rh->hid1]->army.slots[0] = std::pair<ui32,si32>(VLC->creh->nameToID[hpool.heroesPool[rh->hid1]->type->refTypeStack[0]],1);
}
if(rh->flags & 2)
{
hpool.heroesPool[rh->hid2]->army.slots.clear();
hpool.heroesPool[rh->hid2]->army.slots[0] = std::pair<ui32,si32>(VLC->creh->nameToID[hpool.heroesPool[rh->hid2]->type->refTypeStack[0]],1);
}
break;
}
case 500:
@ -622,8 +688,11 @@ void CGameState::applyNL(IPack * pack)
case 3006:
{
BattleAttack *br = static_cast<BattleAttack*>(pack);
CStack *attacker = curB->getStack(br->stackAttacking);
if(br->counter())
curB->getStack(br->stackAttacking)->counterAttacks--;
attacker->counterAttacks--;
if(br->shot())
attacker->shots--;
applyNL(&br->bsa);
break;
}

View File

@ -13,6 +13,7 @@
#include "tchar_amigaos4.h"
#endif
class CTown;
class CScriptCallback;
class CCallback;
class CLuaCallback;
@ -91,6 +92,7 @@ public:
ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
ui16 position; //position on battlefield
ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
si16 shots; //how many shots left
std::set<EAbilities> abilities;
std::set<ECombatInfo> state;
@ -108,6 +110,7 @@ public:
h & id;
creature = &VLC->creh->creatures[id];
abilities = creature->abilities;
shots = creature->shots;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -144,10 +147,12 @@ private:
std::map<int, CGDefInfo*> villages, forts, capitols; //def-info for town graphics
std::vector<ui32> resVals;
struct HeroesPool
struct DLL_EXPORT HeroesPool
{
std::map<ui32,CGHeroInstance *> heroesPool; //[subID] - heroes available to buy; NULL if not available
std::map<ui32,ui8> pavailable; // [subid] -> which players can recruit hero
CGHeroInstance * pickHeroFor(bool native, int player, const CTown *town, int notThatOne=-1);
} hpool; //we have here all heroes available on this map that are not hired
boost::shared_mutex *mx;

View File

@ -231,7 +231,7 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
secSkillAreas[g]->hoverText = std::string(bufor);
}
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);
sprintf(bufor, CGI->generaltexth->allTexts[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->getPrimSkillLevel(3)*10);

View File

@ -310,7 +310,7 @@ void CVisitableOPH::onNAHeroVisit(int objid, int heroID, bool alreadyVisited)
case 102:
{
const CGHeroInstance *h = cb->getHero(heroID);
val = VLC->heroh->reqExp(h->level) + VLC->heroh->reqExp(h->level+val);
val = VLC->heroh->reqExp(h->level+val) - VLC->heroh->reqExp(h->level);
if(!typeOfTree[objid])
{
visitors[objid].insert(heroID);

View File

@ -277,7 +277,7 @@ void processCommand(const std::string &message, CClient *&client)
boost::filesystem::create_directory("Extracted_txts");
tlog0<<"Command accepted. Opening .lod file...\t";
CLodHandler * txth = new CLodHandler;
txth->init(std::string(DATA_DIR "Data" PATHSEPARATOR "H3bitmap.lod"),"data");
txth->init(std::string(DATA_DIR "Data" PATHSEPARATOR "H3bitmap.lod"),"");
tlog0<<"done.\nScanning .lod file\n";
int curp=0;
std::string pattern = ".TXT", pom;

View File

@ -2086,9 +2086,9 @@ void CPlayerInterface::battleStackAttacked(BattleStackAttacked * bsa)
battleInt->displayEffect(bsa->effect, cb->battleGetStackByID(bsa->stackAttacked)->position, cb->battleGetStackByID(bsa->stackAttacked)->attackerOwned);
}
if(bsa->killed())
battleInt->stackKilled(bsa->stackAttacked, bsa->damageAmount, bsa->killedAmount, -1, false);
battleInt->stackKilled(bsa->stackAttacked, bsa->damageAmount, bsa->killedAmount, LOCPLINT->curAction->stackNumber, LOCPLINT->curAction->actionType==7 );
else
battleInt->stackIsAttacked(bsa->stackAttacked, bsa->damageAmount, bsa->killedAmount, -1, false);
battleInt->stackIsAttacked(bsa->stackAttacked, bsa->damageAmount, bsa->killedAmount, LOCPLINT->curAction->stackNumber, LOCPLINT->curAction->actionType==7);
}
void CPlayerInterface::battleAttack(BattleAttack *ba)
{
@ -3129,7 +3129,7 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState
anim = new CCreaturePic(c);
if(!type) anim->anim->setType(1);
char pom[25];int hlp=0;
char pom[75];int hlp=0;
if(creatureCount)
{
@ -3169,7 +3169,10 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState
if(c->shots)
{
printAt(CGI->generaltexth->allTexts[198],155,86,GEOR13,zwykly,bitmap);
SDL_itoa(c->shots,pom,10);
if(State)
sprintf(pom,"%d(%d)",c->shots,State->shotsLeft);
else
SDL_itoa(c->shots,pom,10);
printToWR(pom,276,99,GEOR13,zwykly,bitmap);
}
@ -3930,8 +3933,10 @@ void CTavernWindow::show(SDL_Surface * to)
HeroPortrait *sel = selected ? &h2 : &h1;
char descr[300];
int artifs = sel->h->artifWorn.size()+sel->h->artifacts.size() - 1; //artifacts amount; - 1 is for catapult
if(vstd::contains(sel->h->artifWorn,0)) artifs--; //spellbook doesn't count neither
int artifs = sel->h->artifWorn.size()+sel->h->artifacts.size();
for(int i=13; i<=17; i++) //war machines and spellbook doesn't count
if(vstd::contains(sel->h->artifWorn,i))
artifs--;
sprintf_s(descr,300,CGI->generaltexth->allTexts[215].c_str(),
sel->h->name.c_str(),sel->h->level,sel->h->type->heroClass->name.c_str(),artifs);
printAtMiddleWB(descr,pos.x+146,pos.y+389,GEOR13,40,zwykly,screen);
@ -3984,4 +3989,4 @@ CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const
void CTavernWindow::HeroPortrait::show(SDL_Surface * to)
{
blitAt(graphics->portraitLarge[h->subID],pos);
}
}

View File

@ -64,6 +64,7 @@ si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatur
void CCreatureHandler::loadCreatures()
{
notUsedMonsters += 122,124,126,128,145,146,147,148,149,160,161,162,163,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191;
tlog5 << "\t\tReading ZCRTRAIT.TXT" << std::endl;
std::string buf = bitmaph->getTextFile("ZCRTRAIT.TXT");
int andame = buf.size();
int i=0; //buf iterator
@ -319,21 +320,11 @@ void CCreatureHandler::loadCreatures()
if(ncre.nameSing!=std::string("") && ncre.namePl!=std::string(""))
{
ncre.idNumber = creatures.size();
ncre.isDefinite = true;
creatures.push_back(ncre);
}
}
for(int bb=1; bb<8; ++bb)
{
CCreature ncre;
ncre.isDefinite = false;
ncre.indefLevel = bb;
ncre.indefUpgraded = false;
creatures.push_back(ncre);
ncre.indefUpgraded = true;
creatures.push_back(ncre);
}
tlog5 << "\t\tReading config/crerefnam.txt" << std::endl;
//loading reference names
std::ifstream ifs("config/crerefnam.txt");
int tempi;
@ -350,6 +341,8 @@ void CCreatureHandler::loadCreatures()
ifs.clear();
for(int i=1;i<=10;i++)
levelCreatures.insert(std::pair<int,std::vector<CCreature*> >(i,std::vector<CCreature*>()));
tlog5 << "\t\tReading config/monsters.txt" << std::endl;
ifs.open("config/monsters.txt");
{
while(!ifs.eof())
@ -366,6 +359,7 @@ void CCreatureHandler::loadCreatures()
ifs.close();
ifs.clear();
tlog5 << "\t\tReading config/cr_factions.txt" << std::endl;
ifs.open("config/cr_factions.txt");
while(!ifs.eof())
{
@ -376,6 +370,7 @@ void CCreatureHandler::loadCreatures()
ifs.close();
ifs.clear();
tlog5 << "\t\tReading config/cr_upgrade_list.txt" << std::endl;
ifs.open("config/cr_upgrade_list.txt");
while(!ifs.eof())
{
@ -387,6 +382,7 @@ void CCreatureHandler::loadCreatures()
ifs.clear();
//loading unit animation def names
tlog5 << "\t\tReading config/CREDEFS.TXT" << std::endl;
std::ifstream inp("config/CREDEFS.TXT", std::ios::in | std::ios::binary); //this file is not in lod
inp.seekg(0,std::ios::end); // na koniec
int andame2 = inp.tellg(); // read length
@ -395,11 +391,7 @@ void CCreatureHandler::loadCreatures()
inp.read((char*)bufor, andame2); // read map file to buffer
inp.close();
buf = std::string(bufor);
#ifndef __GNUC__
delete [andame2] bufor;
#else
delete [] bufor;
#endif
i = 0; //buf iterator
hmcr = 0;
@ -409,8 +401,10 @@ void CCreatureHandler::loadCreatures()
break;
}
i+=2;
for(int s=0; s<creatures.size()-16; ++s)
tlog5 << "We have "<<creatures.size() << " creatures\n";
for(int s=0; s<creatures.size(); ++s)
{
//tlog5 <<"\t\t\t" << s <<". Reading defname. \n";
int befi=i;
std::string rub;
for(i; i<andame2; ++i)
@ -430,10 +424,12 @@ void CCreatureHandler::loadCreatures()
std::string defName = buf.substr(befi, i-befi);
creatures[s].animDefName = defName;
}
tlog5 << "\t\tReading CRANIM.TXT.txt" << std::endl;
loadAnimationInfo();
//loading id to projectile mapping
tlog5 << "\t\tReading config/cr_shots.txt" << std::endl;
std::ifstream inp2("config" PATHSEPARATOR "cr_shots.txt", std::ios::in | std::ios::binary); //this file is not in lod
char dump [200];
inp2.getline(dump, 200);
@ -474,8 +470,9 @@ void CCreatureHandler::loadAnimationInfo()
break;
}
i+=2;
for(int dd=0; dd<creatures.size()-16; ++dd)
for(int dd=0; dd<creatures.size(); ++dd)
{
//tlog5 << "\t\t\tReading animation info for creature " << dd << std::endl;
loadUnitAnimInfo(creatures[dd], buf, i);
}
return;

View File

@ -32,13 +32,6 @@ public:
int troopCountLocationOffset, attackClimaxFrame;
///end of anim info
//for some types of towns
bool isDefinite; //if the creature type is wotn dependent, it should be true
int indefLevel; //only if indefinite
bool indefUpgraded; //onlu if inddefinite
//TODO - zdolnoœci (abilities) - na typie wyliczeniowym czy czymœ - albo lepiej secie czegoœ
bool isDoubleWide() const; //returns true if unit is double wide on battlefield
bool isFlying() const; //returns true if it is a flying unit
bool isShooting() const; //returns true if unit can shoot

View File

@ -143,12 +143,13 @@ struct FoWChange : public CPack<FoWChange> //112
struct SetAvailableHeroes : public CPack<SetAvailableHeroes> //113
{
SetAvailableHeroes(){type = 113;};
SetAvailableHeroes(){type = 113;flags=0;};
ui8 player;
ui32 hid1, hid2;
ui8 flags; //1 - reset army of hero1; 2 - reset army of hero 2
template <typename Handler> void serialize(Handler &h, const int version)
{
h & player & hid1 & hid2;
h & player & hid1 & hid2 & flags;
}
};

View File

@ -987,6 +987,11 @@ upgend:
fc.tiles.insert(int3(i,j,k));
sendAndApply(&fc);
}
else if(message == "vcmiglorfindel")
{
CGHeroInstance *hero = gs->getHero(gs->players[*players.begin()].currentSelection);
changePrimSkill(hero->id,4,VLC->heroh->reqExp(hero->level+1) - VLC->heroh->reqExp(hero->level));
}
else
cheated = false;
if(cheated)
@ -1019,12 +1024,26 @@ upgend:
)
break;
CGHeroInstance *nh = gs->players[t->tempOwner].availableHeroes[hid];
HeroRecruited hr;
hr.tid = tid;
hr.hid = nh->subID;
hr.player = t->tempOwner;
hr.tile = t->pos - int3(1,0,0);
sendAndApply(&hr);
SetAvailableHeroes sah;
(hid ? sah.hid2 : sah.hid1) = gs->hpool.pickHeroFor(false,t->tempOwner,t->town)->subID;
(hid ? sah.hid1 : sah.hid2) = gs->players[t->tempOwner].availableHeroes[!hid]->subID;
sah.player = t->tempOwner;
sah.flags = hid+1;
sendAndApply(&sah);
SetResource sr;
sr.player = t->tempOwner;
sr.resid = 6;
sr.val = gs->players[t->tempOwner].resources[6] - 2500;
sendAndApply(&sr);
break;
}
case 2001:
@ -1075,8 +1094,9 @@ upgend:
CStack *curStack = gs->curB->getStack(ba.stackNumber),
*stackAtEnd = gs->curB->getStackT(ba.additionalInfo);
if((curStack->position != ba.destinationTile) || //we wasn't able to reach destination tile
(BattleInfo::mutualPosition(ba.destinationTile,ba.additionalInfo)<0) ) //destination tile is not neighbouring with enemy stack
if( curStack->position != ba.destinationTile //we wasn't able to reach destination tile
|| BattleInfo::mutualPosition(ba.destinationTile,ba.additionalInfo) < 0 //destination tile is not neighbouring with enemy stack
)
return;
BattleAttack bat;
@ -1105,25 +1125,33 @@ upgend:
}
case 7: //shoot
{
//TODO: check arrows count
//TODO: check if stack isn't blocked by enemy
sendAndApply(&StartAction(ba)); //start shooting
CStack *curStack = gs->curB->getStack(ba.stackNumber),
*destStack= gs->curB->getStackT(ba.destinationTile);
if(!curStack //our stack exists
|| !destStack //there is a stack at destination tile
|| !curStack->shots //stack has shots
|| gs->curB->isStackBlocked(curStack->ID) //we are not blocked
|| !vstd::contains(curStack->abilities,SHOOTER) //our stack is shooting unit
)
break;
sendAndApply(&StartAction(ba)); //start shooting
BattleAttack bat;
prepareAttack(bat,curStack,destStack);
bat.flags |= 1;
sendAndApply(&bat);
if(vstd::contains(curStack->abilities,TWICE_ATTACK)
&& curStack->alive())
if(vstd::contains(curStack->abilities,TWICE_ATTACK) //if unit shots twice let's make another shot
&& curStack->alive()
&& destStack->alive()
&& curStack->shots
)
{
prepareAttack(bat,curStack,destStack);
sendAndApply(&bat);
}
sendAndApply(&bat);
sendDataToClients(ui16(3008)); //end shooting
break;
}
@ -1335,25 +1363,15 @@ void CGameHandler::newTurn()
for ( std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++)
{
if(i->first == 255) continue;
if(gs->getDate(1)==7) //first day of week - new heroes in tavern
{
SetAvailableHeroes sah;
sah.player = i->first;
int r;
if(!gs->hpool.heroesPool.size()) return;
for(int a=0;a<2;a++)
{
r = rand() % gs->hpool.heroesPool.size();
std::map<ui32,CGHeroInstance *>::iterator ch = gs->hpool.heroesPool.begin();
while(r--) ch++;
if(a) sah.hid2 = ch->first;
else sah.hid1 = ch->first;
}
//TODO: - will fail when there are not enough available heroes
sah.hid1 = gs->hpool.pickHeroFor(true,i->first,&VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle])->subID;
sah.hid2 = gs->hpool.pickHeroFor(false,i->first,&VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle],sah.hid1)->subID;
sendAndApply(&sah);
//TODO: guarantee that heroes are different
//TODO: first hero should be from initial player town
//TODO: use selectionProbability from CHeroClass
//int town = gs->scenarioOps->getIthPlayersSettings(i->first).castle;
}
if(i->first>=PLAYER_LIMIT) continue;
SetResources r;
@ -1369,7 +1387,7 @@ void CGameHandler::newTurn()
hth.mana = std::max(h->mana,std::min(h->mana+1+h->getSecSkillLevel(8), h->manaLimit())); //hero regains 1 mana point + mysticism lvel
n.heroes.insert(hth);
switch(h->getSecSkillLevel(13)) //handle estates - give gols
switch(h->getSecSkillLevel(13)) //handle estates - give gold
{
case 1: //basic
r.res[6] += 125;