From c8b6858716f65c44dfc7a8fd187280e4c3cd6e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Mon, 20 Apr 2009 22:57:07 +0000 Subject: [PATCH] * mostly done Events objects handling * some moving hero code improvements * fixed Blacksmith * minor changes --- CAdvmapInterface.cpp | 129 +++++++++---------- CCallback.cpp | 27 ---- CCastleInterface.cpp | 4 +- CGameState.cpp | 3 - CMessage.cpp | 25 ++-- CPlayerInterface.cpp | 122 +++++++++++++----- CPlayerInterface.h | 4 +- client/NetPacksClient.cpp | 11 -- hch/CObjectHandler.cpp | 255 ++++++++++++++++++++++++++++++++++++-- hch/CObjectHandler.h | 15 ++- lib/NetPacks.h | 1 + lib/NetPacksLib.cpp | 19 ++- map.cpp | 10 +- server/CGameHandler.cpp | 5 +- 14 files changed, 460 insertions(+), 170 deletions(-) diff --git a/CAdvmapInterface.cpp b/CAdvmapInterface.cpp index bdf1c3548..43f9025da 100644 --- a/CAdvmapInterface.cpp +++ b/CAdvmapInterface.cpp @@ -414,100 +414,95 @@ void CTerrainRect::clickLeft(tribool down) int3 mp = whichTileIsIt(); if ((mp.x<0) || (mp.y<0)) return; - std::vector < const CGObjectInstance * > objs; - if (LOCPLINT->adventureInt->selection->ID != HEROI_TYPE) + + std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mp), //blocking objects at tile + vobjs = LOCPLINT->cb->getVisitableObjs(mp); //visitable objects + + if (LOCPLINT->adventureInt->selection->ID != HEROI_TYPE) //hero is not selected (presumably town) { - if (currentPath) + if(currentPath) { tlog2<<"Warning: Lost path?" << std::endl; delete currentPath; currentPath = NULL; } - objs = LOCPLINT->cb->getBlockingObjs(mp); - for(size_t i=0; i < objs.size(); ++i) + + for(size_t i=0; i < bobjs.size(); ++i) { - if(objs[i]->ID == TOWNI_TYPE && objs[i]->tempOwner == LOCPLINT->playerID) //town + if(bobjs[i]->ID == TOWNI_TYPE && bobjs[i]->getOwner() == LOCPLINT->playerID) //our town clicked { - if(LOCPLINT->adventureInt->selection == (objs[i])) - { - LOCPLINT->openTownWindow(static_cast(objs[i])); - } + if(LOCPLINT->adventureInt->selection == (bobjs[i])) //selected town clicked + LOCPLINT->openTownWindow(static_cast(bobjs[i])); else + LOCPLINT->adventureInt->select(static_cast(bobjs[i])); + + return; + } + else if(bobjs[i]->ID == HEROI_TYPE && bobjs[i]->tempOwner == LOCPLINT->playerID) //hero clicked - select him + { + LOCPLINT->adventureInt->select(static_cast(bobjs[i])); + return; + } + } + } + + else //hero is selected + { + bool townEntrance = false; //town entrance tile has been clicked? + const CGHeroInstance * currentHero = static_cast(LOCPLINT->adventureInt->selection); + + for(size_t i=0; i < vobjs.size(); ++i) + { + if(vobjs[i]->ID == TOWNI_TYPE) + townEntrance = true; + } + + if(!townEntrance) //not entrance - select town or open hero window + { + for(size_t i=0; i < bobjs.size(); ++i) + { + if(bobjs[i]->ID == TOWNI_TYPE && bobjs[i]->tempOwner == LOCPLINT->playerID) //town - switch selection to it { - LOCPLINT->adventureInt->select(static_cast(objs[i])); + LOCPLINT->adventureInt->select(static_cast(bobjs[i])); + return; + } + else if(bobjs[i]->ID == HEROI_TYPE //it's a hero + && bobjs[i]->tempOwner == LOCPLINT->playerID //our hero (is this condition needed?) + && currentHero == (bobjs[i]) ) //and selected one + { + LOCPLINT->openHeroWindow(currentHero); return; } } - else if(objs[i]->ID == HEROI_TYPE && objs[i]->tempOwner == LOCPLINT->playerID) - { - LOCPLINT->adventureInt->select(static_cast(objs[i])); - return; - } } - return; - } - else - { - objs = LOCPLINT->cb->getVisitableObjs(mp); - for(size_t i=0; i < objs.size(); ++i) + + //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise + if (currentPath) { - if(objs[i]->ID == TOWNI_TYPE) - goto endchkpt; - } - objs = LOCPLINT->cb->getBlockingObjs(mp); - for(size_t i=0; i < objs.size(); ++i) - { - if(objs[i]->ID == TOWNI_TYPE && objs[i]->tempOwner == LOCPLINT->playerID) //town + if (currentPath->endPos() == mp) //we'll be moving { - LOCPLINT->adventureInt->select(static_cast(objs[i])); - return; + LOCPLINT->pim->unlock(); + LOCPLINT->moveHero(currentHero,*currentPath); + LOCPLINT->pim->lock(); } - else if(objs[i]->ID == HEROI_TYPE && objs[i]->tempOwner == LOCPLINT->playerID && LOCPLINT->adventureInt->selection == (objs[i])) - { - LOCPLINT->openHeroWindow(static_cast(objs[i])); - return; - } - } - } -endchkpt: - bool mres =true; - if (currentPath) - { - if ( (currentPath->endPos()) == mp) - { //move - CPath sended(*currentPath); //temporary path - engine will operate on it - LOCPLINT->pim->unlock(); - mres = LOCPLINT->moveHero(static_cast(LOCPLINT->adventureInt->selection),&sended); - LOCPLINT->pim->lock(); - if(mres) + else //remove an old path { delete currentPath; - currentPath = NULL; + currentPath=NULL; LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.getPosOfHero(LOCPLINT->adventureInt->selection)].second = NULL; } } - else - { - delete currentPath; - currentPath=NULL; - LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.getPosOfHero(LOCPLINT->adventureInt->selection)].second = NULL; - } - } - const CGHeroInstance * currentHero = (LOCPLINT->adventureInt->heroList.items.size())?(LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].first):(NULL); - if(currentHero) - { - int3 bufpos = currentHero->getPosition(false); - if (mres) + else //remove old path and find a new one { + int3 bufpos = currentHero->getPosition(false); + CPath *& pathForCurhero = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second; if(pathForCurhero) delete pathForCurhero; currentPath = pathForCurhero = LOCPLINT->cb->getPath(bufpos, mp, currentHero);; } - return; - } - + } //end of hero is selected "case" } void CTerrainRect::clickRight(tribool down) { @@ -1318,9 +1313,9 @@ void CAdvMapInt::fmoveHero() return; if (!terrain.currentPath) return; - CPath sended(*(terrain.currentPath)); //temporary path - engine will operate on it + LOCPLINT->pim->unlock(); - LOCPLINT->moveHero(static_cast(LOCPLINT->adventureInt->selection),&sended); + LOCPLINT->moveHero(static_cast(LOCPLINT->adventureInt->selection),*terrain.currentPath); LOCPLINT->pim->lock(); } void CAdvMapInt::fshowSpellbok() diff --git a/CCallback.cpp b/CCallback.cpp index f10d2e05f..34b57cf5e 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -25,7 +25,6 @@ #ifdef max #undef max #endif -extern CSharedCond > mess; /* * CCallback.cpp, part of VCMI engine @@ -67,21 +66,6 @@ bool CCallback::moveHero(const CGHeroInstance *h, int3 dst) const { MoveHero pack(dst,h->id); *cl->serv << &pack; - - {//wait till there is server answer - boost::unique_lock lock(*mess.mx); - while(std::find_if(mess.res->begin(),mess.res->end(),&isType<501>) == mess.res->end()) - mess.cv->wait(lock); - std::set::iterator itr = std::find_if(mess.res->begin(),mess.res->end(),&isType<501>); - TryMoveHero *tmh = dynamic_cast(*itr); - mess.res->erase(itr); - if(!tmh->result) - { - delete tmh; - return false; - } - delete tmh; - } return true; } void CCallback::selectionMade(int selection, int asker) @@ -343,9 +327,6 @@ const CCreatureSet* CCallback::getGarrison(const CGObjectInstance *obj) const int CCallback::swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2) { - if(s1->tempOwner != player || s2->tempOwner != player) - return -1; - ArrangeStacks pack(1,p1,p2,s1->id,s2->id,0); *cl->serv << &pack; return 0; @@ -353,20 +334,12 @@ int CCallback::swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int CCallback::mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2) { - if ((s1->tempOwner!= player || s2->tempOwner!=player)) - { - return -1; - } ArrangeStacks pack(2,p1,p2,s1->id,s2->id,0); *cl->serv << &pack; return 0; } int CCallback::splitStack(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2, int val) { - if (s1->tempOwner!= player || s2->tempOwner!=player || (!val)) - { - return -1; - } ArrangeStacks pack(3,p1,p2,s1->id,s2->id,val); *cl->serv << &pack; return 0; diff --git a/CCastleInterface.cpp b/CCastleInterface.cpp index fc063f579..ded37aaf1 100644 --- a/CCastleInterface.cpp +++ b/CCastleInterface.cpp @@ -581,8 +581,8 @@ void CCastleInterface::buildingClicked(int building) bool possible = (LOCPLINT->cb->getResourceAmount(6) >= price); if(vstd::contains(hero->artifWorn,ui16(aid+9))) //hero already has machine possible = false; - deactivate(); - (new CBlacksmithDialog(possible,CArtHandler::convertMachineID(aid,false),aid,hero->id))->activate(); + + LOCPLINT->pushInt(new CBlacksmithDialog(possible,CArtHandler::convertMachineID(aid,false),aid,hero->id)); break; } default: diff --git a/CGameState.cpp b/CGameState.cpp index 03f6aef39..298798e21 100644 --- a/CGameState.cpp +++ b/CGameState.cpp @@ -898,9 +898,6 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed) if(map->objects[no]->ID==26) { map->objects[no]->defInfo->handler=NULL; - map->removeBlockVisTiles(map->objects[no]); - map->objects[no]->defInfo->blockMap[5] = 255; - map->addBlockVisTiles(map->objects[no]); } map->objects[no]->hoverName = VLC->generaltexth->names[map->objects[no]->ID]; } diff --git a/CMessage.cpp b/CMessage.cpp index a7963acc5..a20f1bac5 100644 --- a/CMessage.cpp +++ b/CMessage.cpp @@ -508,8 +508,11 @@ ComponentResolved::ComponentResolved( SComponent *Comp ) std::vector * brtext = CMessage::breakText(comp->subtitle,11,true,true); //text txt = CMessage::drawText(brtext,GEOR13); delete brtext; - comp->pos.w = img->w; - comp->pos.h = img->h + COMPONENT_TO_SUBTITLE + CMessage::getMaxSizes(txt).second; + + //calculate dimensions + std::pair textSize = CMessage::getMaxSizes(txt); + comp->pos.w = std::max(textSize.first, img->w); //bigger of: subtitle width and image width + comp->pos.h = img->h + COMPONENT_TO_SUBTITLE + textSize.second; } ComponentResolved::~ComponentResolved() @@ -537,16 +540,18 @@ ComponentsToBlit::ComponentsToBlit(std::vector & SComps, int maxw, comps.resize(1); int curw = 0; - int curr = 0; + int curr = 0; //current row for(size_t i=0;igetImg()->w + 12 + (_or ? _or->w : 0)); + ComponentResolved *cur = new ComponentResolved(SComps[i]); + + int toadd = (cur->comp->pos.w + 12 + (_or ? _or->w : 0)); if (curw + toadd > maxw) { curr++; amax(w,curw); - curw = SComps[i]->getImg()->w; + curw = cur->comp->pos.w; comps.resize(curr+1); } else @@ -554,13 +559,13 @@ ComponentsToBlit::ComponentsToBlit(std::vector & SComps, int maxw, curw += toadd; } - comps[curr].push_back(new ComponentResolved(SComps[i])); + comps[curr].push_back(cur); } for(size_t i=0;icomp->pos.h); h += maxh + BETWEEN_COMPS_ROWS; } @@ -575,7 +580,7 @@ void ComponentsToBlit::blitCompsOnSur( SDL_Surface * _or, int inter, int &curh, { ComponentResolved *cur = (comps)[i][j]; totalw += cur->comp->pos.w; - amax(maxh,cur->comp->pos.h); + amax(maxh,cur->comp->pos.h+BETWEEN_COMPS_ROWS); } if(_or) { @@ -594,7 +599,7 @@ void ComponentsToBlit::blitCompsOnSur( SDL_Surface * _or, int inter, int &curh, //blit img int hlp = curh-(cur->comp->pos.h)/2; - blitAt(cur->img,curw,hlp,ret); + blitAt(cur->img, curw + (cur->comp->pos.w - cur->comp->getImg()->w)/2, hlp, ret); cur->comp->pos.x = curw; cur->comp->pos.y = hlp; @@ -603,7 +608,7 @@ void ComponentsToBlit::blitCompsOnSur( SDL_Surface * _or, int inter, int &curh, CMessage::blitTextOnSur(cur->txt, hlp, ret, cur->comp->pos.x + cur->comp->pos.w/2 ); //if there is subsequent component blit "or" - curw += cur->img->w; + curw += cur->comp->pos.w; if(j<((comps)[i].size()-1)) { if(_or) diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index 633bddaba..ca2172969 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -59,12 +59,15 @@ using namespace boost::assign; using namespace CSDL_Ext; -extern TTF_Font * GEOR16; -CPlayerInterface * LOCPLINT; -extern std::queue events; -extern boost::mutex eventsM; void processCommand(const std::string &message, CClient *&client); +extern TTF_Font * GEOR16; +extern std::queue events; +extern boost::mutex eventsM; + +CPlayerInterface * LOCPLINT; +enum EMoveState {STOP_MOVE, WAITING_MOVE, CONTINUE_MOVE, DURING_MOVE}; +CondSh stillMoveHero; //used during hero movement struct OCM_HLP_CGIN { @@ -465,7 +468,7 @@ void CGarrisonInt::createSlots() new CGarrisonSlot(this, pos.x + (i->first*(58+interx)), pos.y + 64 + intery,i->first,1, &CGI->creh->creatures[i->second.first],i->second.second); } - for(int i=0; isize(); i++) + for(int i=0; isize(); i++) if((*sdown)[i] == NULL) (*sdown)[i] = new CGarrisonSlot(this, pos.x + (i*(58+interx)), pos.y + 64 + intery,i,1, NULL, 0); } @@ -680,8 +683,21 @@ void SComponent::init(Etype Type, int Subtype, int Val) subtitle = CGI->arth->artifacts[Subtype].Name(); break; case primskill: - description = CGI->generaltexth->arraytxt[2+Subtype]; - oss << ((Val>0)?("+"):("-")) << Val << " " << CGI->generaltexth->primarySkillNames[Subtype]; + oss << ((Val>0)?("+"):("-")) << Val << " "; + if(Subtype < 4) + { + description = CGI->generaltexth->arraytxt[2+Subtype]; + oss << CGI->generaltexth->primarySkillNames[Subtype]; + } + else if(Subtype == 5) //spell points + { + description = CGI->generaltexth->allTexts[149]; + oss << CGI->generaltexth->allTexts[387]; + } + else + { + tlog1 << "Wrong subtype=" << Subtype << std::endl; + } subtitle = oss.str(); break; case secskill44: case secskill: @@ -697,6 +713,9 @@ void SComponent::init(Etype Type, int Subtype, int Val) description = CGI->spellh->spells[Subtype].descriptions[Val]; subtitle = CGI->spellh->spells[Subtype].name; break; + case creature: + subtitle = boost::lexical_cast(Val) + " " + CGI->creh->creatures[Subtype].*(val != 1 ? &CCreature::namePl : &CCreature::nameSing); + break; case experience: description = CGI->generaltexth->allTexts[241]; oss << Val ; @@ -774,12 +793,15 @@ SDL_Surface * SComponent::getImg() case spell: return graphics->spellscr->ourImages[subtype].bitmap; break; + case creature: + return graphics->bigImgs[subtype]; } return NULL; } void SComponent::clickRight (tribool down) { - LOCPLINT->adventureInt->handleRightClick(description,down,this); + if(description.size()) + LOCPLINT->adventureInt->handleRightClick(description,down,this); } void SComponent::activate() { @@ -1291,6 +1313,7 @@ void CPlayerInterface::heroMoved(const HeroMoveDetails & details) adventureInt->centerOn(details.ho->pos); //actualizing screen pos adventureInt->minimap.draw(screen2); + adventureInt->heroList.draw(screen2); if(details.style>0 || details.src == details.dst) return; @@ -1303,19 +1326,27 @@ void CPlayerInterface::heroMoved(const HeroMoveDetails & details) if(ho->movement > 50) ho->moveDir = getDir(details.src,details.dst); ho->isStanding = true; - //adventureInt->heroList.draw(); - if (adventureInt->terrain.currentPath && ho->movement>145) //TODO: better condition on movement - check cost of endtile + + if(ho->movement) { delete adventureInt->terrain.currentPath; adventureInt->terrain.currentPath = NULL; adventureInt->heroList.items[adventureInt->heroList.getPosOfHero(ho)].second = NULL; } + stillMoveHero.setn(STOP_MOVE); return; } if (adventureInt->terrain.currentPath) //&& hero is moving { adventureInt->terrain.currentPath->nodes.erase(adventureInt->terrain.currentPath->nodes.end()-1); + if(!adventureInt->terrain.currentPath->nodes.size()) + { + + delete adventureInt->terrain.currentPath; + adventureInt->terrain.currentPath = NULL; + adventureInt->heroList.items[adventureInt->heroList.getPosOfHero(ho)].second = NULL; + } } @@ -1767,16 +1798,20 @@ void CPlayerInterface::heroMoved(const HeroMoveDetails & details) switch(ev->type) { case SDL_MOUSEBUTTONDOWN: - stillMoveHero = false; + stillMoveHero.setn(STOP_MOVE); break; case SDL_KEYDOWN: if(ev->key.keysym.sym < SDLK_F1) - stillMoveHero = false; + stillMoveHero.setn(STOP_MOVE); break; } delete ev; } } + + if(stillMoveHero.get() == 1) + stillMoveHero.setn(DURING_MOVE); + } void CPlayerInterface::heroKilled(const CGHeroInstance* hero) { @@ -2145,11 +2180,10 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID, void CPlayerInterface::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) //called by engine when battle starts; side=0 - left, side=1 - right { - boost::unique_lock un(*pim); - while(showingDialog->get()) SDL_Delay(20); + boost::unique_lock un(*pim); battleInt = new CBattleInterface(army1, army2, hero1, hero2, genRect(600, 800, (conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2)); pushInt(battleInt); } @@ -2370,7 +2404,16 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector & components) { + { + boost::unique_lock un(showingDialog->mx); + while(showingDialog->data) + showingDialog->cond.wait(un); + } + boost::unique_lock un(*pim); + + if(stillMoveHero.get() == DURING_MOVE)//if we are in the middle of hero movement + stillMoveHero.setn(STOP_MOVE); //after showing dialog movement will be stopped std::vector > > pom; pom.push_back(std::pair >("IOKAY.DEF",0)); @@ -2480,9 +2523,9 @@ void CPlayerInterface::availableCreaturesChanged( const CGTownInstance *town ) boost::unique_lock un(*pim); if(castleInt) { - //CFortScreen *fs = dynamic_cast(); - //if(fs) - // fs->draw(castleInt,false); + CFortScreen *fs = dynamic_cast(listInt.front()); + if(fs) + fs->draw(castleInt,false); } } @@ -2523,26 +2566,26 @@ void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero) adventureInt->infoBar.draw(screen); } -bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath * path ) +bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath path ) { - if (!h || !path) + if (!h) return false; //can't find hero bool result = false; - path->convert(0); - stillMoveHero = true; + path.convert(0); + boost::unique_lock un(stillMoveHero.mx); + stillMoveHero.data = CONTINUE_MOVE; - for(int i=path->nodes.size()-1; i>0; i--) + for(int i=path.nodes.size()-1; i>0 && stillMoveHero.data == CONTINUE_MOVE; i--) { - { - boost::unique_lock un(*pim); - if(!stillMoveHero) - return result; - } - int3 endpos(path->nodes[i-1].coord.x, path->nodes[i-1].coord.y, h->pos.z); - result = cb->moveHero(h,endpos); + stillMoveHero.data = WAITING_MOVE; + + int3 endpos(path.nodes[i-1].coord.x, path.nodes[i-1].coord.y, h->pos.z); + cb->moveHero(h,endpos); + while(stillMoveHero.data != STOP_MOVE && stillMoveHero.data != CONTINUE_MOVE) + stillMoveHero.cond.wait(un); } - stillMoveHero = false; + //stillMoveHero = false; return result; } @@ -2553,6 +2596,19 @@ bool CPlayerInterface::shiftPressed() const void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, boost::function &onEnd ) { + { + boost::unique_lock un(showingDialog->mx); + while(showingDialog->data) + showingDialog->cond.wait(un); + } + + boost::unique_lock un(*pim); + while(dialogs.size()) + { + pim->unlock(); + SDL_Delay(20); + pim->lock(); + } CGarrisonWindow *cgw = new CGarrisonWindow(up,down); cgw->quit->callback += onEnd; pushInt(cgw); @@ -2621,6 +2677,12 @@ void CPlayerInterface::totalRedraw() objsToBlit.back()->showAll(screen); } +void CPlayerInterface::requestRealized( PackageApplied *pa ) +{ + if(stillMoveHero.get() == DURING_MOVE) + stillMoveHero.setn(CONTINUE_MOVE); +} + CStatusBar::CStatusBar(int x, int y, std::string name, int maxw) { bg=BitmapHandler::loadBitmap(name); diff --git a/CPlayerInterface.h b/CPlayerInterface.h index bd448c742..8cb1bfa31 100644 --- a/CPlayerInterface.h +++ b/CPlayerInterface.h @@ -559,7 +559,6 @@ public: CCallback * cb; //to communicate with engine const BattleAction *curAction; //during the battle - action currently performed by active stack (or NULL) - bool stillMoveHero; //during hero movement - setting this flag to false will stop movement std::list dialogs; //queue of dialogs awaiting to be shown (not currently shown!) std::list listInt; //list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on) @@ -603,6 +602,7 @@ public: void yourTurn(); void availableCreaturesChanged(const CGTownInstance *town); void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it + void requestRealized(PackageApplied *pa); void serialize(COSer &h, const int version); //saving void serialize(CISer &h, const int version); //loading @@ -638,7 +638,7 @@ public: int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on void showInfoDialog(const std::string &text, const std::vector & components); void showYesNoDialog(const std::string &text, const std::vector & components, CFunctionList onYes, CFunctionList onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close - bool moveHero(const CGHeroInstance *h, CPath * path); + bool moveHero(const CGHeroInstance *h, CPath path); CPlayerInterface(int Player, int serial);//c-tor ~CPlayerInterface();//d-tor diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 5734f216b..808e1c904 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -32,8 +32,6 @@ * */ -CSharedCond > mess(new std::set); - void SetResources::applyCl( CClient *cl ) { cl->playerint[player]->receivedResource(-1,-1); @@ -168,15 +166,6 @@ void TryMoveHero::applyCl( CClient *cl ) i->second->heroMoved(hmd); } } - - //add info for callback - if(result<2) - { - mess.mx->lock(); - mess.res->insert(new TryMoveHero(*this)); - mess.mx->unlock(); - mess.cv->notify_all(); - } } void SetGarrisons::applyCl( CClient *cl ) diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index d1da64565..f32bea590 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -670,8 +670,12 @@ std::vector > CGHeroInstance::getCurrentMoraleModifie //various morale bonuses (from buildings, artifacts, etc) for(std::list::const_iterator i=bonuses.begin(); i != bonuses.end(); i++) + { if(i->type == HeroBonus::MORALE || i->type == HeroBonus::MORALE_AND_LUCK) + { ret.push_back(std::make_pair(i->val, i->description)); + } + } //leadership if(getSecSkillLevel(6)) @@ -2223,22 +2227,257 @@ void CGEvent::onHeroVisit( const CGHeroInstance * h ) const activated(h); } -void CGEvent::endBattle( BattleResult *result ) const +void CGEvent::endBattle( const CGHeroInstance *h, BattleResult *result ) const { if(result->winner) return; - //give + + giveContents(h,true); } void CGEvent::activated( const CGHeroInstance * h ) const +{ + if(army) + { + InfoWindow iw; + iw.player = h->tempOwner; + iw.text << message; + cb->showInfoDialog(&iw); + cb->startBattleI(h->id,army,pos,boost::bind(&CGEvent::endBattle,this,h,_1)); + } + else + { + giveContents(h,false); + } +} + +void CGEvent::giveContents( const CGHeroInstance *h, bool afterBattle ) const { InfoWindow iw; - iw.player = h->tempOwner; - iw.text << message; - cb->showInfoDialog(&iw); - if(guarders) - cb->startBattleI(h->id,guarders,pos,boost::bind(&CGEvent::endBattle,this,_1)); - cb->removeObject(id); + iw.player = h->getOwner(); + + bool changesPrimSkill = false; + for (int i = 0; i < primskills.size(); i++) + { + if(primskills[i]) + { + changesPrimSkill = true; + break; + } + } + + if(gainedExp || changesPrimSkill || abilities.size()) + { + getText(iw,afterBattle,175,h); + + if(gainedExp) + iw.components.push_back(Component(Component::EXPERIENCE,0,gainedExp,0)); + for(int i=0; ishowInfoDialog(&iw); + + //give exp + if(gainedExp) + cb->changePrimSkill(h->id,5,gainedExp,false); + //give prim skills + for(int i=0; ichangePrimSkill(h->id,i,primskills[i],false); + + //give sec skills + for(int i=0; igetSecSkillLevel(abilities[i]); + + if(curLev && curLev < abilityLevels[i] + || h->secSkills.size() < SKILL_PER_HERO ) + { + cb->changeSecSkill(h->id,abilities[i],abilityLevels[i],true); + } + } + + } + + if(manaDiff) + { + getText(iw,afterBattle,luckDiff,176,177,h); + iw.components.push_back(Component(Component::PRIM_SKILL,5,manaDiff,0)); + cb->showInfoDialog(&iw); + cb->setManaPoints(h->id, h->mana + manaDiff); + } + + if(moraleDiff) + { + getText(iw,afterBattle,luckDiff,178,179,h); + iw.components.push_back(Component(Component::MORALE,0,moraleDiff,0)); + cb->showInfoDialog(&iw); + GiveBonus gb; + gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::MORALE,HeroBonus::OBJECT,moraleDiff,id,""); + gb.hid = h->id; + cb->giveHeroBonus(&gb); + } + + if(luckDiff) + { + getText(iw,afterBattle,luckDiff,180,181,h); + iw.components.push_back(Component(Component::LUCK,0,luckDiff,0)); + cb->showInfoDialog(&iw); + GiveBonus gb; + gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT,luckDiff,id,""); + gb.hid = h->id; + cb->giveHeroBonus(&gb); + } + + iw.components.clear(); + iw.text.clear(); + for(int i=0; ishowInfoDialog(&iw); + } + + iw.components.clear(); + iw.text.clear(); + for(int i=0; i 0) + iw.components.push_back(Component(Component::RESOURCE,i,resources[i],0)); + } + if(iw.components.size()) + { + getText(iw,afterBattle,183,h); + cb->showInfoDialog(&iw); + } + + iw.components.clear(); + for(int i=0; ishowInfoDialog(&iw); + } + + for(int i=0; igiveResource(h->getOwner(),i,resources[i]); + + for(int i=0; igiveHeroArtifact(artifacts[i],h->id,-2); + + //show dialog with given creatures + iw.components.clear(); + iw.text.clear(); + for(std::map >::const_iterator i = creatures.slots.begin(); i != creatures.slots.end(); i++) + { + iw.components.push_back(Component(Component::CREATURE,i->second.first,i->second.second,0)); + } + if(iw.components.size()) + { + if(afterBattle) + { + if(iw.components.front().val == 1) + { + iw.text.addTxt(MetaString::ADVOB_TXT,185);//A %s joins %s's army. + iw.text.replacements.push_back(VLC->creh->creatures[iw.components.front().subtype].nameSing); + } + else + { + iw.text.addTxt(MetaString::ADVOB_TXT,186);//%s join %s's army. + iw.text.replacements.push_back(VLC->creh->creatures[iw.components.front().subtype].namePl); + } + iw.text.replacements.push_back(h->name); + } + else + { + iw.text << message; + afterBattle = true; + } + cb->showInfoDialog(&iw); + } + + //check if creatures can be moved to hero army + CCreatureSet heroArmy = h->army; + CCreatureSet ourArmy = creatures; + while(ourArmy) + { + int slot = heroArmy.getSlotFor(ourArmy.slots.begin()->second.first); + if(slot < 0) + break; + + heroArmy.slots[slot].first = ourArmy.slots.begin()->second.first; + heroArmy.slots[slot].second += ourArmy.slots.begin()->second.second; + ourArmy.slots.erase(ourArmy.slots.begin()); + } + + if(!ourArmy) //all creatures can be moved to hero army - do that + { + SetGarrisons sg; + sg.garrs[h->id] = heroArmy; + cb->sendAndApply(&sg); + } + else //show garrison window and let player pick creatures + { + SetGarrisons sg; + sg.garrs[id] = creatures; + cb->sendAndApply(&sg); + + if(removeAfterVisit) + cb->showGarrisonDialog(id,h->id,boost::bind(&IGameCallback::removeObject,cb,id)); + else + cb->showGarrisonDialog(id,h->id,0); + return; + } + + if(!afterBattle) + { + iw.text << message; + cb->showInfoDialog(&iw); + } + + if(removeAfterVisit) + cb->removeObject(id); +} + +void CGEvent::getText( InfoWindow &iw, bool &afterBattle, int text, const CGHeroInstance * h ) const +{ + if(afterBattle) + { + iw.text.addTxt(MetaString::ADVOB_TXT,text);//%s has lost treasure. + iw.text.replacements.push_back(h->name); + } + else + { + iw.text << message; + afterBattle = true; + } +} + +void CGEvent::getText( InfoWindow &iw, bool &afterBattle, int val, int positive, int negative, const CGHeroInstance * h ) const +{ + iw.components.clear(); + iw.text.clear(); + if(afterBattle) + { + iw.text.addTxt(MetaString::ADVOB_TXT,val < 0 ? negative : positive); //%s's luck takes a turn for the worse / %s's luck increases + iw.text.replacements.push_back(h->name); + } + else + { + iw.text << message; + afterBattle = true; + } } void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index b283e87af..71f3f4fed 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -41,6 +41,7 @@ class CArtifact; class CGDefInfo; class CSpecObjInfo; struct TerrainTile; +struct InfoWindow; class DLL_EXPORT CCastleEvent { @@ -375,10 +376,9 @@ public: } }; -class DLL_EXPORT CGEvent : public CGObjectInstance //event objects +class DLL_EXPORT CGEvent : public CArmedInstance //event objects { public: - CCreatureSet guarders; std::string message; ui32 gainedExp; si32 manaDiff; //amount of gained / lost mana @@ -394,18 +394,23 @@ public: ui8 availableFor; //players whom this event is available for ui8 computerActivate; //true if computre player can activate this event ui8 humanActivate; //true if human player can activate this event + ui8 removeAfterVisit; //true if event is removed after occurring template void serialize(Handler &h, const int version) { - h & static_cast(*this); - h & guarders & message & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills + h & static_cast(*this); + h & message & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills & abilities & abilityLevels & artifacts & spells & creatures & availableFor & computerActivate & humanActivate; } void activated(const CGHeroInstance * h) const; void onHeroVisit(const CGHeroInstance * h) const; - void endBattle(BattleResult *result) const; + void endBattle(const CGHeroInstance *h, BattleResult *result) const; + void giveContents(const CGHeroInstance *h, bool afterBattle) const; + + void getText( InfoWindow &iw, bool &afterBattle, int val, int positive, int negative, const CGHeroInstance * h ) const; + void getText( InfoWindow &iw, bool &afterBattle, int text, const CGHeroInstance * h ) const; }; class DLL_EXPORT CGCreature : public CArmedInstance //creatures on map diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 247e3f01e..9ab55f4a4 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -101,6 +101,7 @@ struct MetaString : public CPack //2001 helper for object scrips strings.clear(); texts.clear(); message.clear(); + replacements.clear(); } MetaString(){type = 2001;}; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 3ee37f49d..006167401 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -10,6 +10,8 @@ #include "../hch/CSpellHandler.h" #include #include +#include +#include #include #include @@ -166,7 +168,22 @@ DLL_EXPORT void GiveBonus::applyGs( CGameState *gs ) { CGHeroInstance *h = gs->getHero(hid); h->bonuses.push_back(bonus); - h->bonuses.back().description = toString(bdescr); + + + std::string &descr = h->bonuses.back().description; + + if(!bdescr.texts.size() + && bonus.source == HeroBonus::OBJECT + && (bonus.type == HeroBonus::LUCK || bonus.type == HeroBonus::MORALE || bonus.type == HeroBonus::MORALE_AND_LUCK) + && gs->map->objects[bonus.id]->ID == 26) //it's morale/luck bonus from an event without description + { + descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle" + boost::replace_first(descr,"%d",boost::lexical_cast(std::abs(bonus.val))); + } + else + { + descr = toString(bdescr); + } } DLL_EXPORT void ChangeObjPos::applyGs( CGameState *gs ) diff --git a/map.cpp b/map.cpp index 5d7e9308d..129624084 100644 --- a/map.cpp +++ b/map.cpp @@ -1325,6 +1325,10 @@ void Mapa::readDefInfo( unsigned char * bufor, int &i) } else vinya->visitDir = 0xff; + + if(vinya->id == 26) + std::memset(vinya->blockMap,255,6); + defy.push_back(vinya); // add this def to the vector } } @@ -1366,7 +1370,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i) } if(bufor[i++]) { - evnt->guarders = readCreatureSet(bufor,i,7,(version>RoE)); + evnt->army = readCreatureSet(bufor,i,7,(version>RoE)); } i+=4; } @@ -1415,7 +1419,9 @@ void Mapa::readObjects( unsigned char * bufor, int &i) i+=8; evnt->availableFor = readNormalNr(bufor,i, 1); ++i; evnt->computerActivate = readNormalNr(bufor,i, 1); ++i; - evnt->humanActivate = readNormalNr(bufor,i, 1); ++i; + evnt->removeAfterVisit = readNormalNr(bufor,i, 1); ++i; + evnt->humanActivate = true; + i+=4; break; } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 52cb05bbf..c8212690d 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -409,8 +409,6 @@ askInterfaceForMove: //end battle, remove all info, free memory giveExp(*battleResult.data); sendAndApply(battleResult.data); - if(cb) - cb(battleResult.data); //if one hero has lost we will erase him if(battleResult.data->winner!=0 && hero1) @@ -430,6 +428,9 @@ askInterfaceForMove: if(battleResult.data->exp[1] && hero2) changePrimSkill(hero2->id,4,battleResult.data->exp[1]); + if(cb) + cb(battleResult.data); + delete battleResult.data; }