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

* added heroes pool for heroes available for hiring

* better handling disposed/predefined heroes
* blocked scrolling adventure map with mouse when left ctrl is pressed
* scholar will be accessible from the top
* partially done tavern and hero recruitment
* fixed bug with formation button in hero window
* unified hero initialization code
* minor changes

For 0.63c dev release
This commit is contained in:
Michał W. Urbańczyk 2008-10-26 20:58:34 +00:00
parent 45204d8beb
commit 3a66dc2b7c
25 changed files with 646 additions and 241 deletions

View File

@ -1132,12 +1132,12 @@ void CAdvMapInt::activate()
}
void CAdvMapInt::deactivate()
{
KeyInterested::deactivate();
if(subInt == heroWindow)
{
heroWindow->deactivate();
return;
}
KeyInterested::deactivate();
hide();
}
void CAdvMapInt::show(SDL_Surface *to)

View File

@ -627,4 +627,21 @@ void CCallback::setFormation(const CGHeroInstance * hero, bool tight)
void CCallback::setSelection(const CArmedInstance * obj)
{
*cl->serv << ui16(514) << obj->id;
}
}
void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)
{
ui8 i=0;
for(;i<gs->players[player].availableHeroes.size();i++)
if(gs->players[player].availableHeroes[i] == hero)
break;
if(i>1) return;
*cl->serv << ui16(515) << town->id << i;
}
std::vector<const CGHeroInstance *> CCallback::getAvailableHeroes(const CGTownInstance * town) const
{
std::vector<const CGHeroInstance *> ret(gs->players[player].availableHeroes.size());
std::copy(gs->players[player].availableHeroes.begin(),gs->players[player].availableHeroes.end(),ret.begin());
return ret;
}

View File

@ -44,6 +44,7 @@ public:
virtual void trade(int mode, int id1, int id2, int val1)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
virtual void setFormation(const CGHeroInstance * hero, bool tight)=0;
virtual void setSelection(const CArmedInstance * obj)=0;
virtual void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)=0;
//get info
virtual bool verifyPath(CPath * path, bool blockSea)const =0;
@ -68,6 +69,7 @@ public:
virtual void getMarketOffer(int t1, int t2, int &give, int &rec, int mode=0)const =0;
virtual std::vector < const CGObjectInstance * > getFlaggableObjects(int3 pos) const =0;
virtual int3 getMapSize() const =0; //returns size of map - z is 1 for one - level map and 2 for two level map
virtual std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const =0; //heroes that can be recruited
//battle
virtual int battleGetBattlefieldType()=0; // 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
@ -127,6 +129,7 @@ public:
void trade(int mode, int id1, int id2, int val1);
void setFormation(const CGHeroInstance * hero, bool tight);
void setSelection(const CArmedInstance * obj);
void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero);
//get info
bool verifyPath(CPath * path, bool blockSea) const;
@ -153,6 +156,7 @@ public:
void getMarketOffer(int t1, int t2, int &give, int &rec, int mode=0) const;
std::vector < const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const; //heroes that can be recruited
//battle
int battleGetBattlefieldType(); // 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

@ -478,7 +478,7 @@ void CCastleInterface::buildingClicked(int building)
{
switch(building)
{
case 0: case 1: case 2: case 3: case 4:
case 0: case 1: case 2: case 3: case 4: //mage guild
{
if(town->visitingHero && !vstd::contains(town->visitingHero->artifWorn,ui16(17))) //visiting hero doesn't have spellboks
{
@ -500,11 +500,18 @@ void CCastleInterface::buildingClicked(int building)
{
deactivate();
enterMageGuild();
}
break;
}
case 7: case 8: case 9:
case 5: //tavern
{
std::vector<const CGHeroInstance*> h = LOCPLINT->cb->getAvailableHeroes(town);
CTavernWindow *tv = new CTavernWindow(h[0],h[1],"GOSSIP TEST");
deactivate();
tv->activate();
break;
}
case 7: case 8: case 9: //fort/citadel/castle
{
deactivate();
CFortScreen *fs = new CFortScreen(this);
@ -512,22 +519,22 @@ void CCastleInterface::buildingClicked(int building)
fs->show();
break;
}
case 10: case 11: case 12: case 13:
case 10: case 11: case 12: case 13: //hall
enterHall();
break;
case 14:
case 14: //marketplace
{
deactivate();
CMarketplaceWindow *cmw = new CMarketplaceWindow(0);
cmw->activate();
break;
}
case 15:
case 15: //resource silo
{
LOCPLINT->showInfoDialog(CGI->buildh->buildings[town->subID][15]->description,std::vector<SComponent*>());
break;
}
case 16:
case 16: //blacksmith
{
const CGHeroInstance *hero = town->visitingHero;
if(!hero)

View File

@ -88,10 +88,10 @@ void CConsoleHandler::setColor(int level)
int CConsoleHandler::run()
{
char buffer[500];
char buffer[5000];
while(true)
{
std::cin.getline(buffer, 500);
std::cin.getline(buffer, 5000);
if(cb && *cb)
(*cb)(buffer);
}

View File

@ -28,6 +28,7 @@ boost::rand48 ran;
#undef max
#endif
CGObjectInstance * createObject(int id, int subid, int3 pos, int owner)
{
CGObjectInstance * nobj;
@ -35,39 +36,11 @@ CGObjectInstance * createObject(int id, int subid, int3 pos, int owner)
{
case 34: //hero
{
CGHeroInstance * nobj;
nobj = new CGHeroInstance();
CGHeroInstance * nobj = new CGHeroInstance();
nobj->pos = pos;
nobj->tempOwner = owner;
nobj->defInfo = new CGDefInfo();
nobj->defInfo->id = 34;
nobj->defInfo->subid = subid;
nobj->defInfo->printPriority = 0;
nobj->defInfo->visitDir = 0xff;
nobj->type = VLC->heroh->heroes[subid];
for(int i=0;i<6;i++)
{
nobj->defInfo->blockMap[i]=255;
nobj->defInfo->visitMap[i]=0;
}
nobj->ID = id;
nobj->subID = subid;
nobj->defInfo->handler=NULL;
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->secSkills = nobj->type->secSkillsInit; //copying initial secondary skills
nobj->mana = 10 * nobj->getPrimSkillLevel(3);
//nobj->initHero(ran);
return nobj;
}
case 98: //town
@ -93,12 +66,6 @@ CGObjectInstance * createObject(int id, int subid, int3 pos, int owner)
if(nobj->ID==34 || nobj->ID==98)
return nobj;
nobj->defInfo = VLC->dobjinfo->gobjs[id][subid];
//if(!nobj->defInfo->handler)
//{
// nobj->defInfo->handler = CDefHandler::giveDef(nobj->defInfo->name);
// nobj->defInfo->width = nobj->defInfo->handler->ourImages[0].bitmap->w/32;
// nobj->defInfo->height = nobj->defInfo->handler->ourImages[0].bitmap->h/32;
//}
return nobj;
}
CStack * BattleInfo::getStack(int stackID)
@ -428,6 +395,14 @@ void CGameState::applyNL(IPack * pack)
players[rh->player].fogOfWarMap[t.x][t.y][t.z] = rh->mode;
break;
}
case 113:
{
SetAvailableHeroes *rh = static_cast<SetAvailableHeroes*>(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]);
break;
}
case 500:
{
RemoveObject *rh = static_cast<RemoveObject*>(pack);
@ -543,6 +518,31 @@ void CGameState::applyNL(IPack * pack)
h->artifWorn = sha->artifWorn;
break;
}
case 515:
{
HeroRecruited *sha = static_cast<HeroRecruited*>(pack);
CGHeroInstance *h = hpool.heroesPool[sha->hid];
CGTownInstance *t = getTown(sha->tid);
h->setOwner(sha->player);
h->pos = sha->tile;
h->movement = h->maxMovePoints(true);
hpool.heroesPool.erase(sha->hid);
if(h->id < 0)
{
h->id = map->objects.size();
map->objects.push_back(h);
}
else
map->objects[h->id] = h;
map->heroes.push_back(h);
players[h->tempOwner].heroes.push_back(h);
map->addBlockVisTiles(h);
t->visitingHero = h;
h->visitedTown = t;
h->inTownGarrison = false;
break;
}
case 1001://set object property
{
SetObjectProperty *p = static_cast<SetObjectProperty*>(pack);
@ -987,6 +987,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
break;
}
}
nnn->initHero();
map->heroes.push_back(nnn);
map->objects.push_back(nnn);
map->addBlockVisTiles(nnn);
@ -1037,82 +1038,41 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
}
/*************************HEROES************************************************/
std::set<int> hids;
for(int i=0; i<map->allowedHeroes.size(); i++) //add to hids all allowed heroes
if(map->allowedHeroes[i])
hids.insert(i);
for (int i=0; i<map->heroes.size();i++) //heroes instances
{
if (map->heroes[i]->getOwner()<0)
{
tlog2 << "Warning - hero with uninitialized owner!\n";
continue;
}
CGHeroInstance * vhi = (map->heroes[i]);
if(!vhi->type)
vhi->type = VLC->heroh->heroes[vhi->subID];
if (vhi->level<1)
{
vhi->exp=40+ran()%50;
vhi->level = 1;
}
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()<PRIMARY_SKILLS)
vhi->primSkills.resize(PRIMARY_SKILLS);
vhi->primSkills[0] = vhi->type->heroClass->initialAttack;
vhi->primSkills[1] = vhi->type->heroClass->initialDefence;
vhi->primSkills[2] = vhi->type->heroClass->initialPower;
vhi->primSkills[3] = vhi->type->heroClass->initialKnowledge;
}
vhi->mana = vhi->getPrimSkillLevel(3)*10;
if (!vhi->name.length())
{
vhi->name = vhi->type->name;
}
if (!vhi->biography.length())
{
vhi->biography = vhi->type->biography;
}
if (vhi->portrait < 0)
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
{
int pom, pom2=0;
for(int x=0;x<3;x++)
{
pom = (VLC->creh->nameToID[vhi->type->refTypeStack[x]]);
if(pom>=145 && pom<=149) //war machine
{
pom2++;
switch (pom)
{
case 145: //catapult
vhi->artifWorn[16] = 3;
break;
default:
vhi->artifWorn[9+CArtHandler::convertMachineID(pom,true)] = CArtHandler::convertMachineID(pom,true);
break;
}
continue;
}
vhi->army.slots[x-pom2].first = pom;
if((pom = (vhi->type->highStack[x]-vhi->type->lowStack[x])) > 0)
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;
}
}
vhi->initHero();
players[vhi->getOwner()].heroes.push_back(vhi);
hids.erase(vhi->subID);
}
for(int i=0; i<map->predefinedHeroes.size(); i++)
{
if(!vstd::contains(hids,map->predefinedHeroes[i]->subID))
continue;
map->predefinedHeroes[i]->initHero();
hpool.heroesPool[map->predefinedHeroes[i]->subID] = map->predefinedHeroes[i];
hpool.pavailable[map->predefinedHeroes[i]->subID] = 0xff;
hids.erase(map->predefinedHeroes[i]->subID);
}
BOOST_FOREACH(int hid, hids) //all not used allowed heroes go into the pool
{
CGHeroInstance * vhi = new CGHeroInstance();
vhi->initHero(hid);
hpool.heroesPool[hid] = vhi;
hpool.pavailable[hid] = 0xff;
}
for(int i=0; i<map->disposedHeroes.size(); i++)
{
hpool.pavailable[map->disposedHeroes[i].ID] = map->disposedHeroes[i].players;
}
/*************************FOG**OF**WAR******************************************/
for(std::map<ui8, PlayerState>::iterator k=players.begin(); k!=players.end(); ++k)

View File

@ -47,6 +47,7 @@ public:
std::vector<si32> resources;
std::vector<CGHeroInstance *> heroes;
std::vector<CGTownInstance *> towns;
std::vector<CGHeroInstance *> availableHeroes; //heroes available in taverns
PlayerState():color(-1),currentSelection(0xffffffff){};
};
@ -142,7 +143,12 @@ private:
std::map<ui8,PlayerState> players; //ID <-> playerstate
std::map<int, CGDefInfo*> villages, forts, capitols; //def-info for town graphics
std::vector<ui32> resVals;
std::vector<CGHeroInstance *> heroesPool; //[subID] - heroes available to buy; NULL if not available
struct 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
} hpool; //we have here all heroes available on this map that are not hired
boost::shared_mutex *mx;

View File

@ -316,8 +316,9 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
gar2button->callback2 = vstd::assigno(hero->tacticFormationEnabled,false);
}
formations->onChange = boost::bind(&CCallback::setFormation, LOCPLINT->cb, Hero, _1);
formations->onChange = 0;
formations->select(hero->army.formation,true);
formations->onChange = boost::bind(&CCallback::setFormation, LOCPLINT->cb, Hero, _1);
redrawCurBack();
}

View File

@ -225,6 +225,7 @@ int main(int argc, char** argv)
#ifndef __unix__
::console->killConsole(console->native_handle());
#endif
LOCPLINT->pim->lock();
SDL_Delay(750);
tlog0 << "Ending...\n";
exit(0);

View File

@ -1608,8 +1608,10 @@ void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
}
void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(graphics->heroWins.find(hero->subID)==graphics->heroWins.end())
graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hero->subID,infoWin(hero)));
adventureInt->heroList.updateHList();
}
void CPlayerInterface::openTownWindow(const CGTownInstance * town)
{
@ -1682,37 +1684,40 @@ void CPlayerInterface::handleMouseMotion(SDL_Event *sEvent)
(*i)->mouseMoved(sEvent->motion);
}
}
if(sEvent->motion.x<15)
if(!SDL_GetKeyState(NULL)[SDLK_LCTRL])
{
LOCPLINT->adventureInt->scrollingLeft = true;
}
else
{
LOCPLINT->adventureInt->scrollingLeft = false;
}
if(sEvent->motion.x>screen->w-15)
{
LOCPLINT->adventureInt->scrollingRight = true;
}
else
{
LOCPLINT->adventureInt->scrollingRight = false;
}
if(sEvent->motion.y<15)
{
LOCPLINT->adventureInt->scrollingUp = true;
}
else
{
LOCPLINT->adventureInt->scrollingUp = false;
}
if(sEvent->motion.y>screen->h-15)
{
LOCPLINT->adventureInt->scrollingDown = true;
}
else
{
LOCPLINT->adventureInt->scrollingDown = false;
if(sEvent->motion.x<15)
{
LOCPLINT->adventureInt->scrollingLeft = true;
}
else
{
LOCPLINT->adventureInt->scrollingLeft = false;
}
if(sEvent->motion.x>screen->w-15)
{
LOCPLINT->adventureInt->scrollingRight = true;
}
else
{
LOCPLINT->adventureInt->scrollingRight = false;
}
if(sEvent->motion.y<15)
{
LOCPLINT->adventureInt->scrollingUp = true;
}
else
{
LOCPLINT->adventureInt->scrollingUp = false;
}
if(sEvent->motion.y>screen->h-15)
{
LOCPLINT->adventureInt->scrollingDown = true;
}
else
{
LOCPLINT->adventureInt->scrollingDown = false;
}
}
}
void CPlayerInterface::handleEvent(SDL_Event *sEvent)
@ -3842,3 +3847,138 @@ void CSystemOptionsWindow::show(SDL_Surface *to)
backToMap->show(to);
heroMoveSpeed->show(to);
}
CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, const std::string &gossip)
:h1(selected,0,72,299,H1),h2(selected,1,162,299,H2)
{
selected = 0;
bg = BitmapHandler::loadBitmap("TPTAVERN.bmp");
graphics->blueToPlayersAdv(bg,LOCPLINT->playerID);
printAtMiddle(CGI->generaltexth->jktexts[37],200,35,GEOR16,tytulowy,bg);
printAtMiddle("2500",320,328,GEOR13,zwykly,bg);
printAtMiddle(CGI->generaltexth->jktexts[38],146,283,GEOR16,tytulowy,bg);
printAtMiddleWB(gossip,200,220,GEOR13,50,zwykly,bg);
pos.w = bg->w;
pos.h = bg->h;
pos.x = (screen->w-bg->w)/2;
pos.y = (screen->h-bg->h)/2;
h1.pos.x += pos.x;
h2.pos.x += pos.x;
h1.pos.y += pos.y;
h2.pos.y += pos.y;
cancel = new AdventureMapButton("","",boost::bind(&CTavernWindow::close,this),pos.x+310,pos.y+428,"ICANCEL.DEF",SDLK_ESCAPE);
recruit = new AdventureMapButton("","",boost::bind(&CTavernWindow::recruitb,this),pos.x+272,pos.y+355,"TPTAV01.DEF",SDLK_RETURN);
thiefGuild = new AdventureMapButton("","",0,pos.x+22,pos.y+428,"TPTAV02.DEF",SDLK_t);
}
void CTavernWindow::recruitb()
{
const CGHeroInstance *toBuy = (selected ? h2 : h1).h;
close();
LOCPLINT->cb->recruitHero(LOCPLINT->castleInt->town,toBuy);
}
CTavernWindow::~CTavernWindow()
{
SDL_FreeSurface(bg);
delete cancel;
delete thiefGuild;
delete recruit;
}
void CTavernWindow::activate()
{
LOCPLINT->objsToBlit += this;
LOCPLINT->curint->subInt = this;
thiefGuild->activate();
cancel->activate();
h1.activate();
h2.activate();
recruit->activate();
}
void CTavernWindow::deactivate()
{
LOCPLINT->objsToBlit -= this;
thiefGuild->deactivate();
cancel->deactivate();
h1.deactivate();
h2.deactivate();
recruit->deactivate();
}
void CTavernWindow::close()
{
LOCPLINT->curint->subInt = NULL;
deactivate();
delete this;
LOCPLINT->curint->activate();
}
void CTavernWindow::show(SDL_Surface * to)
{
blitAt(bg,pos.x,pos.y,screen);
h1.show();
h2.show();
thiefGuild->show();
cancel->show();
recruit->show();
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
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);
CSDL_Ext::drawBorder(screen,sel->pos.x-2,sel->pos.y-2,sel->pos.w+4,sel->pos.h+4,int3(247,223,123));
}
void CTavernWindow::HeroPortrait::clickLeft(boost::logic::tribool down)
{
if(pressedL && !down)
as();
ClickableL::clickLeft(down);
}
void CTavernWindow::HeroPortrait::activate()
{
ClickableL::activate();
ClickableR::activate();
}
void CTavernWindow::HeroPortrait::deactivate()
{
ClickableL::deactivate();
ClickableR::deactivate();
}
void CTavernWindow::HeroPortrait::clickRight(boost::logic::tribool down)
{
if(down)
{
LOCPLINT->adventureInt->heroWindow->setHero(h);
LOCPLINT->objsToBlit += LOCPLINT->adventureInt->heroWindow;
LOCPLINT->curint->deactivate();
ClickableR::activate();
}
else if(vstd::contains(LOCPLINT->objsToBlit,LOCPLINT->adventureInt->heroWindow))
{
LOCPLINT->objsToBlit -= LOCPLINT->adventureInt->heroWindow;
ClickableR::deactivate();
LOCPLINT->castleInt->showAll(0,true);
LOCPLINT->curint->subInt->activate();
}
}
CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H)
:as(sel,id)
{
h = H;
pos.x = x;
pos.y = y;
pos.w = 58;
pos.h = 64;
}
void CTavernWindow::HeroPortrait::show(SDL_Surface * to)
{
blitAt(graphics->portraitLarge[h->subID],pos);
}

View File

@ -109,8 +109,8 @@ public:
ClickableL();
virtual ~ClickableL(){};
virtual void clickLeft (boost::logic::tribool down)=0;
virtual void activate()=0;
virtual void deactivate()=0;
virtual void activate();
virtual void deactivate();
};
class ClickableR : public virtual CIntObject //for right-clicks
{
@ -663,6 +663,37 @@ public:
void show(SDL_Surface * to = NULL);
};
class CTavernWindow : public IShowActivable, public CIntObject
{
public:
class HeroPortrait : public ClickableL, public ClickableR
{
public:
vstd::assigner<int,int> as;
const CGHeroInstance *h;
void activate();
void deactivate();
void clickLeft(boost::logic::tribool down);
void clickRight(boost::logic::tribool down);
HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H);
void show(SDL_Surface * to = NULL);
} h1, h2;
SDL_Surface *bg;
int selected;//0 (left) or 1 (right)
AdventureMapButton *thiefGuild, *cancel, *recruit;
CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, const std::string &gossip); //c-tor
~CTavernWindow(); //d-tor
void recruitb();
void close();
void activate();
void deactivate();
void show(SDL_Surface * to = NULL);
};
extern CPlayerInterface * LOCPLINT;
#endif //CPLAYERINTERFACE_H

View File

@ -1,3 +1,33 @@
0.63 -> 0.64 (Nov 01 2008 ?)
* sprites from /Sprites folder are handled correctly now
* several fixes for pathfinder and path arrows
* clicking on a tile in advmap view when a path is shown will not only hide it but also calculate a new one
* water elemental will really be treated as 2 hex creature
* potential infinite loop in reverseCreature removed
* better handling of battle cursor
* better handling disposed/predefined heroes
* fixed blocked shooter behavior
* slowed map scrolling
* blocked scrolling adventure map with mouse when left ctrl is pressed
* blocked map scrolling when dialog window is opened
* it's possible in battles to check remeaining HP of neutral stacks
* heroes regain 1 mana point each turn
* support for mistycisim and intelligence skills
* partial support for Magic Arrow spell
* fixed memory leak
* fixed bug with dying unit
* scholar will be accessible from the top
* partially done tavern and hero recruitment
* minor changes
* Added some kind of simple chatting functionality through console. Implemented several WoG cheats equivalents:
a) woggaladriel -> vcmiainur
b) wogoliphaunt -> vcminoldor
c) wogshadowfax -> vcminahar
d) wogeyeofsauron -> vcmieagles
e) wogisengard -> vcmiformenos
f) wogsaruman -> vcmiistari
g) wogpathofthedead -> vcmiangband
0.62 -> 0.63 (Oct 01 2008)
GENERAL:
* coloured console output, logging all info to txt files

View File

@ -42,11 +42,9 @@ struct StartInfo
for(unsigned int i=0; i<playerInfos.size(); ++i)
if(playerInfos[i].color == no)
return playerInfos[i];
#ifndef __GNUC__
throw new std::exception("Cannot find info about player");
#else
throw new std::exception();
#endif
tlog1 << "Cannot find info about player " << no <<". Throwing...\n";
throw std::string("Cannot find info about player");
}
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -300,6 +300,14 @@ void CClient::process(int what)
playerint[fc.player]->tileHidden(fc.tiles);
break;
}
case 113:
{
SetAvailableHeroes sav;
*serv >> sav;
tlog5 << "Setting available heroes for player "<<(int)sav.player<<std::endl;
gs->apply(&sav);
break;
}
case 500:
{
RemoveObject rh;
@ -438,6 +446,19 @@ void CClient::process(int what)
tlog4 << "Player "<<(int)color<<" sends a message: " << message << std::endl;
break;
}
case 515:
{
HeroRecruited hr;
*serv >> hr;
tlog5 << "New hero bought\n";
CGHeroInstance *h = gs->hpool.heroesPool[hr.hid];
gs->apply(&hr);
CGI->mh->initHeroDef(h);
//CGI->mh->printObject(h);
playerint[h->tempOwner]->heroCreated(h);
playerint[h->tempOwner]->heroInGarrisonChange(gs->getTown(hr.tid));
break;
}
case 1001:
{
SetObjectProperty sop;

View File

@ -18,7 +18,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
#define THC
#endif
#define NAME_VER ("VCMI 0.63")
#define NAME_VER ("VCMI 0.63c")
#define CONSOLE_LOGGING_LEVEL 5
#define FILE_LOGGING_LEVEL 6

View File

@ -66,7 +66,7 @@ void CDefObjInfoHandler::load()
inp>>nobj->id;
inp>>nobj->subid;
inp>>nobj->type;
if(nobj->type == 2 || nobj->type == 3 || nobj->type == 4 || nobj->type == 5 || nobj->id == 111 || nobj->id == 33) //creature, hero, artifact, resource or whripool or garrison
if(nobj->type == 2 || nobj->type == 3 || nobj->type == 4 || nobj->type == 5 || nobj->id == 111 || nobj->id == 33 || nobj->id == 81) //creature, hero, artifact, resource or whirlpool or garrison or scholar
nobj->visitDir = 0xff;
else
nobj->visitDir = (8|16|32|64|128); //disabled visiting from the top

View File

@ -16,10 +16,12 @@ void CGeneralTextHandler::load()
}
i+=2;
std::string buflet;
for(int jj=0; jj<764; ++jj)
{
std::string buflet;
loadToIt(buflet, buf, i, 2);
if(buflet[0] == '"' && buflet[buflet.size()-1] == '"')
buflet = buflet.substr(1,buflet.size()-2);
allTexts.push_back(buflet);
}

View File

@ -6,11 +6,14 @@
#include "CDefObjInfoHandler.h"
#include "CHeroHandler.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/random/linear_congruential.hpp>
#include "CTownHandler.h"
#include "CArtHandler.h"
#include "../lib/VCMI_Lib.h"
DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
extern CLodHandler * bitmaph;
extern boost::rand48 ran;
void CObjectHandler::loadObjects()
{
VLC->objh = this;
@ -307,6 +310,57 @@ int CGHeroInstance::getSecSkillLevel(const int & ID) const
return secSkills[i].second;
return 0;
}
int lowestSpeed(const CGHeroInstance * chi)
{
std::map<si32,std::pair<ui32,si32> >::const_iterator i = chi->army.slots.begin();
int ret = VLC->creh->creatures[(*i++).second.first].speed;
for (;i!=chi->army.slots.end();i++)
{
ret = std::min(ret,VLC->creh->creatures[(*i).second.first].speed);
}
return ret;
}
int CGHeroInstance::maxMovePoints(bool onLand) const
{
int ret = 1270+70*lowestSpeed(this);
if (ret>2000)
ret=2000;
if(onLand)
{
//logistics:
switch(getSecSkillLevel(2))
{
case 1:
ret *= 1.1f;
break;
case 2:
ret *= 1.2f;
break;
case 3:
ret *= 1.3f;
break;
}
}
else
{
//navigation:
switch(getSecSkillLevel(2))
{
case 1:
ret *= 1.5f;
break;
case 2:
ret *= 2.0f;
break;
case 3:
ret *= 2.5f;
break;
}
}
return ret;
}
ui32 CGHeroInstance::getArtAtPos(ui16 pos) const
{
if(pos<19)
@ -348,7 +402,6 @@ const CArtifact * CGHeroInstance::getArt(int pos) const
else
return NULL;
}
int CGTownInstance::getSightDistance() const //returns sight distance
{
return 10;
@ -442,7 +495,6 @@ bool CGTownInstance::hasCapitol() const
}
CGTownInstance::CGTownInstance()
{
pos = int3(-1,-1,-1);
builded=-1;
destroyed=-1;
garrisonHero=NULL;
@ -452,9 +504,13 @@ CGTownInstance::CGTownInstance()
CGObjectInstance::CGObjectInstance(): animPhaseShift(rand()%0xff)
{
pos = int3(-1,-1,-1);
//std::cout << "Tworze obiekt "<<this<<std::endl;
//state = new CLuaObjectScript();
ID = subID = id = -1;
defInfo = NULL;
state = NULL;
info = NULL;
tempOwner = 254;
blockVisit = false;
}
@ -467,13 +523,102 @@ CGObjectInstance::~CGObjectInstance()
}
CGHeroInstance::CGHeroInstance()
{
ID = 34;
tacticFormationEnabled = inTownGarrison = false;
portrait = level = exp = -1;
mana = movement = portrait = level = -1;
isStanding = true;
moveDir = 4;
mana = 0;
exp = 0;
visitedTown = NULL;
type = NULL;
secSkills.push_back(std::make_pair(-1, -1));
}
void CGHeroInstance::initHero(int SUBID)
{
subID = SUBID;
initHero();
}
void CGHeroInstance::initHero()
{
if(!defInfo)
{
defInfo = new CGDefInfo();
defInfo->id = 34;
defInfo->subid = subID;
defInfo->printPriority = 0;
defInfo->visitDir = 0xff;
}
if(!type)
type = VLC->heroh->heroes[subID];
for(int i=0;i<6;i++)
{
defInfo->blockMap[i]=255;
defInfo->visitMap[i]=0;
}
defInfo->handler=NULL;
defInfo->blockMap[5] = 253;
defInfo->visitMap[5] = 2;
artifWorn[16] = 3;
if(type->heroType % 2 == 1) //it's a magical hero
{
artifWorn[17] = 0; //give him spellbook
}
if(portrait < 0)
portrait = subID;
if((!primSkills.size()) || (primSkills[0]<0))
{
primSkills.resize(4);
primSkills[0] = type->heroClass->initialAttack;
primSkills[1] = type->heroClass->initialDefence;
primSkills[2] = type->heroClass->initialPower;
primSkills[3] = type->heroClass->initialKnowledge;
}
if(secSkills.size() == 1 && secSkills[0] == std::make_pair(-1, -1)) //set secondary skills to default
secSkills = type->secSkillsInit;
if(mana < 0)
mana = manaLimit();
if (!name.length())
name = type->name;
if (!biography.length())
biography = type->biography;
if (level<1)
{
exp=40+ (ran()) % 50;
level = 1;
}
if (!army.slots.size()) //standard army//initial army
{
int pom, pom2=0;
for(int x=0;x<3;x++)
{
pom = (VLC->creh->nameToID[type->refTypeStack[x]]);
if(pom>=145 && pom<=149) //war machine
{
pom2++;
switch (pom)
{
case 145: //catapult
artifWorn[16] = 3;
break;
default:
artifWorn[9+CArtHandler::convertMachineID(pom,true)] = CArtHandler::convertMachineID(pom,true);
break;
}
continue;
}
army.slots[x-pom2].first = pom;
if((pom = (type->highStack[x]-type->lowStack[x])) > 0)
army.slots[x-pom2].second = (ran()%pom)+type->lowStack[x];
else
army.slots[x-pom2].second = +type->lowStack[x];
army.formation = false;
}
}
}
CGHeroInstance::~CGHeroInstance()

View File

@ -128,9 +128,12 @@ public:
int getCurrentMorale() const;
int getPrimSkillLevel(int id) const;
int getSecSkillLevel(const int & ID) const; //0 - no skill
int maxMovePoints(bool onLand) const;
ui32 getArtAtPos(ui16 pos) const; //-1 - no artifact
void setArtAtPos(ui16 pos, int art);
const CArtifact * getArt(int pos) const;
void initHero();
void initHero(int SUBID);
CGHeroInstance();
virtual ~CGHeroInstance();
};

View File

@ -140,6 +140,18 @@ struct FoWChange : public CPack<FoWChange> //112
h & tiles & player;
}
};
struct SetAvailableHeroes : public CPack<SetAvailableHeroes> //113
{
SetAvailableHeroes(){type = 113;};
ui8 player;
ui32 hid1, hid2;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & player & hid1 & hid2;
}
};
struct RemoveObject : public CPack<RemoveObject> //500
{
RemoveObject(){type = 500;};
@ -220,6 +232,19 @@ struct SetHeroArtifacts : public CPack<SetHeroArtifacts> //509
h & hid & artifacts & artifWorn;
}
};
struct HeroRecruited : public CPack<HeroRecruited> //515
{
HeroRecruited(){type = 515;};
si32 hid, tid; //subID of hero
int3 tile;
ui8 player;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & hid & tid & tile & player;
}
};
struct NewTurn : public CPack<NewTurn> //101
{
struct Hero

59
map.cpp
View File

@ -1015,15 +1015,38 @@ void Mapa::loadTown( CGObjectInstance * &nobj, unsigned char * bufor, int &i )
void Mapa::loadHero( CGObjectInstance * &nobj, unsigned char * bufor, int &i )
{
CGHeroInstance * nhi = new CGHeroInstance;
int identifier = 0;
if(version>RoE)
{
identifier = readNormalNr(bufor,i, 4); i+=4;
}
nobj->setOwner(bufor[i]); ++i;
nobj->subID = readNormalNr(bufor,i, 1); ++i;
for(int j=0; j<predefinedHeroes.size(); j++)
{
if(predefinedHeroes[j]->subID == nobj->subID)
{
*nhi = *predefinedHeroes[j];
break;
}
}
(*(static_cast<CGObjectInstance*>(nhi))) = *nobj;
delete nobj;
nobj=nhi;
if(version>RoE)
nhi->portrait = nhi->subID;
for(int j=0; j<disposedHeroes.size(); j++)
{
nhi->identifier = readNormalNr(bufor,i, 4); i+=4;
if(disposedHeroes[j].ID == nhi->subID)
{
nhi->name = disposedHeroes[j].name;
nhi->portrait = disposedHeroes[j].portrait;
break;
}
}
nhi->setOwner(bufor[i]); ++i;
nhi->subID = readNormalNr(bufor,i, 1); ++i;
nhi->identifier = identifier;
if(readChar(bufor,i))//true if hero has nonstandard name
nhi->name = readString(bufor,i);
if(version>AB)
@ -1038,10 +1061,7 @@ void Mapa::loadHero( CGObjectInstance * &nobj, unsigned char * bufor, int &i )
bool portrait=bufor[i]; ++i;
if (portrait)
i++; //TODO read portrait nr, save, open
else
nhi->portrait = nhi->subID;
nhi->portrait = readChar(bufor,i);
if(readChar(bufor,i))//true if hero has specified abilities
{
int howMany = readNormalNr(bufor,i); i+=4;
@ -1052,10 +1072,6 @@ 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
@ -1471,15 +1487,16 @@ void Mapa::readHeader( unsigned char * bufor, int &i)
int lenbuf = readNormalNr(bufor,i); i+=4;
for (int zz=0; zz<lenbuf; zz++)
disposedHeroes[g].name+=bufor[i++];
int players = bufor[i++];
for(int zz=0;zz<8;zz++)
{
int por = (1<<zz);
if(players & por)
disposedHeroes[g].players[zz] = true;
else
disposedHeroes[g].players[zz] = false;
}
disposedHeroes[g].players = bufor[i++];
//int players = bufor[i++];
//for(int zz=0;zz<8;zz++)
//{
// int por = (1<<zz);
// if(players & por)
// disposedHeroes[g].players[zz] = true;
// else
// disposedHeroes[g].players[zz] = false;
//}
}
}

2
map.h
View File

@ -356,7 +356,7 @@ struct DLL_EXPORT DisposedHero
int ID;
int portrait; //0xFF - default
std::string name;
bool players[8]; //who can hire this hero
ui8 players; //who can hire this hero (bitfield)
};
class DLL_EXPORT CMapEvent

View File

@ -481,6 +481,12 @@ void processDef (CGDefInfo* def)
}
}
}
void CMapHandler::initHeroDef(CGHeroInstance * h)
{
h->defInfo->handler = graphics->flags1[0];
h->defInfo->width = h->defInfo->handler->ourImages[0].bitmap->w/32;
h->defInfo->height = h->defInfo->handler->ourImages[0].bitmap->h/32;
}
void CMapHandler::init()
{
timeHandler th;
@ -512,9 +518,7 @@ void CMapHandler::init()
{
if(!map->heroes[i]->defInfo->handler)
{
map->heroes[i]->defInfo->handler = graphics->flags1[0];
map->heroes[i]->defInfo->width = map->heroes[i]->defInfo->handler->ourImages[0].bitmap->w/32;
map->heroes[i]->defInfo->height = map->heroes[i]->defInfo->handler->ourImages[0].bitmap->h/32;
initHeroDef(map->heroes[i]);
}
}

View File

@ -89,6 +89,7 @@ public:
bool printObject(const CGObjectInstance * obj); //puts appropriate things to ttiles, so obj will be visible on map
bool hideObject(const CGObjectInstance * obj); //removes appropriate things from ttiles, so obj will be no longer visible on map (but still will exist)
bool removeObject(CGObjectInstance * obj); //removes object from each place in VCMI (I hope)
void initHeroDef(CGHeroInstance * h);
void init();
void calculateBlockedPos();
void initObjectRects();

View File

@ -1005,6 +1005,28 @@ upgend:
gs->players[*players.begin()].currentSelection = id;
break;
}
case 515:
{
ui32 tid;
ui8 hid;
c >> tid >> hid;
CGTownInstance *t = gs->getTown(tid);
if(!vstd::contains(players,t->tempOwner) //not our town
|| !vstd::contains(t->builtBuildings,5) //no tavern in the town
|| gs->players[t->tempOwner].resources[6]<2500 //not enough gold
|| t->visitingHero //there is visiting hero - no place
|| gs->players[t->tempOwner].heroes.size()>7 //8 hero limit
)
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);
break;
}
case 2001:
{
ui32 qid, answer;
@ -1303,67 +1325,36 @@ void CGameHandler::init(StartInfo *si, int Seed)
//delete lf;
}
int lowestSpeed(CGHeroInstance * chi)
{
std::map<si32,std::pair<ui32,si32> >::iterator i = chi->army.slots.begin();
int ret = VLC->creh->creatures[(*i++).second.first].speed;
for (;i!=chi->army.slots.end();i++)
{
ret = std::min(ret,VLC->creh->creatures[(*i).second.first].speed);
}
return ret;
}
int valMovePoints(CGHeroInstance * chi, bool onLand)
{
int ret = 1270+70*lowestSpeed(chi);
if (ret>2000)
ret=2000;
if(onLand)
{
//logistics:
switch(chi->getSecSkillLevel(2))
{
case 1:
ret *= 1.1f;
break;
case 2:
ret *= 1.2f;
break;
case 3:
ret *= 1.3f;
break;
}
}
else
{
//navigation:
switch(chi->getSecSkillLevel(2))
{
case 1:
ret *= 1.5f;
break;
case 2:
ret *= 2.0f;
break;
case 3:
ret *= 2.5f;
break;
}
}
//TODO: additional bonuses (but they aren't currently stored in chi)
return ret;
}
void CGameHandler::newTurn()
{
tlog5 << "Turn " << gs->day+1 << std::endl;
NewTurn n;
n.day = gs->day + 1;
n.resetBuilded = true;
for ( std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++)
{
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;
}
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;
r.player = i->first;
@ -1374,7 +1365,7 @@ void CGameHandler::newTurn()
{
NewTurn::Hero hth;
hth.id = h->id;
hth.move = valMovePoints(h, true); //TODO: check if hero is really on the land
hth.move = h->maxMovePoints(true); //TODO: check if hero is really on the land
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);
@ -1423,6 +1414,7 @@ void CGameHandler::newTurn()
n.res.push_back(r);
}
sendAndApply(&n);
tlog5 << "Info about turn " << n.day << "has been sent!" << std::endl;
for (std::set<CCPPObjectScript *>::iterator i=cppscripts.begin();i!=cppscripts.end();i++)
{
(*i)->newTurn();