From 3a66dc2b7c1017e0dc0a1276989833f57245b2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Sun, 26 Oct 2008 20:58:34 +0000 Subject: [PATCH] * 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 --- CAdvmapInterface.cpp | 2 +- CCallback.cpp | 19 +++- CCallback.h | 4 + CCastleInterface.cpp | 21 ++-- CConsoleHandler.cpp | 4 +- CGameState.cpp | 172 ++++++++++++------------------- CGameState.h | 8 +- CHeroWindow.cpp | 3 +- CMT.cpp | 1 + CPlayerInterface.cpp | 200 ++++++++++++++++++++++++++++++------ CPlayerInterface.h | 35 ++++++- ChangeLog | 30 ++++++ StartInfo.h | 8 +- client/Client.cpp | 21 ++++ global.h | 2 +- hch/CDefObjInfoHandler.cpp | 2 +- hch/CGeneralTextHandler.cpp | 4 +- hch/CObjectHandler.cpp | 153 ++++++++++++++++++++++++++- hch/CObjectHandler.h | 3 + lib/NetPacks.h | 25 +++++ map.cpp | 59 +++++++---- map.h | 2 +- mapHandler.cpp | 10 +- mapHandler.h | 1 + server/CGameHandler.cpp | 98 ++++++++---------- 25 files changed, 646 insertions(+), 241 deletions(-) diff --git a/CAdvmapInterface.cpp b/CAdvmapInterface.cpp index 65421c4cf..1406f9dd4 100644 --- a/CAdvmapInterface.cpp +++ b/CAdvmapInterface.cpp @@ -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) diff --git a/CCallback.cpp b/CCallback.cpp index 7edaf4216..c7a40eb78 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -627,4 +627,21 @@ void CCallback::setFormation(const CGHeroInstance * hero, bool tight) void CCallback::setSelection(const CArmedInstance * obj) { *cl->serv << ui16(514) << obj->id; -} \ No newline at end of file +} + +void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *hero) +{ + ui8 i=0; + for(;iplayers[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 CCallback::getAvailableHeroes(const CGTownInstance * town) const +{ + std::vector ret(gs->players[player].availableHeroes.size()); + std::copy(gs->players[player].availableHeroes.begin(),gs->players[player].availableHeroes.end(),ret.begin()); + return ret; +} \ No newline at end of file diff --git a/CCallback.h b/CCallback.h index b6da96b63..8ec5fc708 100644 --- a/CCallback.h +++ b/CCallback.h @@ -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 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 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 diff --git a/CCastleInterface.cpp b/CCastleInterface.cpp index 939707147..d002af759 100644 --- a/CCastleInterface.cpp +++ b/CCastleInterface.cpp @@ -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 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()); break; } - case 16: + case 16: //blacksmith { const CGHeroInstance *hero = town->visitingHero; if(!hero) diff --git a/CConsoleHandler.cpp b/CConsoleHandler.cpp index 743aba83d..ab1fce233 100644 --- a/CConsoleHandler.cpp +++ b/CConsoleHandler.cpp @@ -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); } diff --git a/CGameState.cpp b/CGameState.cpp index 658ded96c..830dd87f8 100644 --- a/CGameState.cpp +++ b/CGameState.cpp @@ -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(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(pack); @@ -543,6 +518,31 @@ void CGameState::applyNL(IPack * pack) h->artifWorn = sha->artifWorn; break; } + case 515: + { + HeroRecruited *sha = static_cast(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(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 hids; + for(int i=0; iallowedHeroes.size(); i++) //add to hids all allowed heroes + if(map->allowedHeroes[i]) + hids.insert(i); for (int i=0; iheroes.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()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; ipredefinedHeroes.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; idisposedHeroes.size(); i++) + { + hpool.pavailable[map->disposedHeroes[i].ID] = map->disposedHeroes[i].players; } /*************************FOG**OF**WAR******************************************/ for(std::map::iterator k=players.begin(); k!=players.end(); ++k) diff --git a/CGameState.h b/CGameState.h index ab802973b..85519c6a2 100644 --- a/CGameState.h +++ b/CGameState.h @@ -47,6 +47,7 @@ public: std::vector resources; std::vector heroes; std::vector towns; + std::vector availableHeroes; //heroes available in taverns PlayerState():color(-1),currentSelection(0xffffffff){}; }; @@ -142,7 +143,12 @@ private: std::map players; //ID <-> playerstate std::map villages, forts, capitols; //def-info for town graphics std::vector resVals; - std::vector heroesPool; //[subID] - heroes available to buy; NULL if not available + + struct HeroesPool + { + std::map heroesPool; //[subID] - heroes available to buy; NULL if not available + std::map 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; diff --git a/CHeroWindow.cpp b/CHeroWindow.cpp index 76862524f..631074fd6 100644 --- a/CHeroWindow.cpp +++ b/CHeroWindow.cpp @@ -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(); } diff --git a/CMT.cpp b/CMT.cpp index 63ea49969..c7ecf1b35 100644 --- a/CMT.cpp +++ b/CMT.cpp @@ -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); diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index b1fa3ec35..ce0f7b91a 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -1608,8 +1608,10 @@ void CPlayerInterface::heroKilled(const CGHeroInstance* hero) } void CPlayerInterface::heroCreated(const CGHeroInstance * hero) { + boost::unique_lock un(*pim); if(graphics->heroWins.find(hero->subID)==graphics->heroWins.end()) graphics->heroWins.insert(std::pair(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); +} \ No newline at end of file diff --git a/CPlayerInterface.h b/CPlayerInterface.h index e2f85ce25..965b5236a 100644 --- a/CPlayerInterface.h +++ b/CPlayerInterface.h @@ -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 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 diff --git a/ChangeLog b/ChangeLog index 8c6cba9e2..dca775541 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/StartInfo.h b/StartInfo.h index 86a79ecb9..04269370f 100644 --- a/StartInfo.h +++ b/StartInfo.h @@ -42,11 +42,9 @@ struct StartInfo for(unsigned int i=0; i void serialize(Handler &h, const int version) { diff --git a/client/Client.cpp b/client/Client.cpp index a2ea958de..ef903f0ce 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -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<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; diff --git a/global.h b/global.h index 574cae0b5..4052f3b48 100644 --- a/global.h +++ b/global.h @@ -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 diff --git a/hch/CDefObjInfoHandler.cpp b/hch/CDefObjInfoHandler.cpp index 6abce35c1..4200c18ca 100644 --- a/hch/CDefObjInfoHandler.cpp +++ b/hch/CDefObjInfoHandler.cpp @@ -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 diff --git a/hch/CGeneralTextHandler.cpp b/hch/CGeneralTextHandler.cpp index b2ebe1a88..519c246fd 100644 --- a/hch/CGeneralTextHandler.cpp +++ b/hch/CGeneralTextHandler.cpp @@ -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); } diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index d273173f1..f20ffb0ba 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -6,11 +6,14 @@ #include "CDefObjInfoHandler.h" #include "CHeroHandler.h" #include +#include #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 >::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 "<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() diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index dfc989d3f..9fdc0a09c 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -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(); }; diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 5ef2249e9..a884eb67a 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -140,6 +140,18 @@ struct FoWChange : public CPack //112 h & tiles & player; } }; + +struct SetAvailableHeroes : public CPack //113 +{ + SetAvailableHeroes(){type = 113;}; + ui8 player; + ui32 hid1, hid2; + template void serialize(Handler &h, const int version) + { + h & player & hid1 & hid2; + } +}; + struct RemoveObject : public CPack //500 { RemoveObject(){type = 500;}; @@ -220,6 +232,19 @@ struct SetHeroArtifacts : public CPack //509 h & hid & artifacts & artifWorn; } }; + +struct HeroRecruited : public CPack //515 +{ + HeroRecruited(){type = 515;}; + si32 hid, tid; //subID of hero + int3 tile; + ui8 player; + + template void serialize(Handler &h, const int version) + { + h & hid & tid & tile & player; + } +}; struct NewTurn : public CPack //101 { struct Hero diff --git a/map.cpp b/map.cpp index 71c0d9861..8ae717098 100644 --- a/map.cpp +++ b/map.cpp @@ -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; jsubID == nobj->subID) + { + *nhi = *predefinedHeroes[j]; + break; + } + } + (*(static_cast(nhi))) = *nobj; delete nobj; nobj=nhi; - if(version>RoE) + nhi->portrait = nhi->subID; + + for(int j=0; jidentifier = 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; zzdefInfo->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]); } } diff --git a/mapHandler.h b/mapHandler.h index d018bd219..77477b3f4 100644 --- a/mapHandler.h +++ b/mapHandler.h @@ -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(); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 375ae3f98..be5b923a6 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -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 >::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::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::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::iterator i=cppscripts.begin();i!=cppscripts.end();i++) { (*i)->newTurn();