diff --git a/client/BattleInterface/CBattleAnimations.cpp b/client/BattleInterface/CBattleAnimations.cpp index 965ed7e5b..db4dde3d4 100644 --- a/client/BattleInterface/CBattleAnimations.cpp +++ b/client/BattleInterface/CBattleAnimations.cpp @@ -244,7 +244,7 @@ void CDefenceAnimation::nextFrame() if(!myAnim()->onLastFrameInGroup()) { - if( myAnim()->getType() == CCreatureAnim::DEATH && (owner->animCount+1)%(4/owner->curInt->sysOpts.animSpeed)==0 + if( myAnim()->getType() == CCreatureAnim::DEATH && (owner->animCount+1)%(4/owner->getAnimSpeed())==0 && !myAnim()->onLastFrameInGroup() ) { myAnim()->incrementFrame(); @@ -625,7 +625,7 @@ void CMovementStartAnimation::nextFrame() } else { - if((owner->animCount+1)%(4/owner->curInt->sysOpts.animSpeed)==0) + if((owner->animCount+1)%(4/owner->getAnimSpeed())==0) myAnim()->incrementFrame(); } } diff --git a/client/BattleInterface/CBattleInterface.cpp b/client/BattleInterface/CBattleInterface.cpp index a2356965b..cd28eff35 100644 --- a/client/BattleInterface/CBattleInterface.cpp +++ b/client/BattleInterface/CBattleInterface.cpp @@ -117,7 +117,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe queue = new CStackQueue(embedQueue, this); if(!embedQueue) { - if(curInt->sysOpts.showQueue) + if(settings["battle"]["showQueue"].Bool()) pos.y += queue->pos.h / 2; //center whole window queue->moveTo(Point(pos.x, pos.y - queue->pos.h)); @@ -423,24 +423,26 @@ CBattleInterface::~CBattleInterface() void CBattleInterface::setPrintCellBorders(bool set) { - curInt->sysOpts.printCellBorders = set; - curInt->sysOpts.settingsChanged(); + Settings cellBorders = settings.write["battle"]["cellBorders"]; + cellBorders->Bool() = set; + redrawBackgroundWithHexes(activeStack); GH.totalRedraw(); } void CBattleInterface::setPrintStackRange(bool set) { - curInt->sysOpts.printStackRange = set; - curInt->sysOpts.settingsChanged(); + Settings stackRange = settings.write["battle"]["stackRange"]; + stackRange->Bool() = set; + redrawBackgroundWithHexes(activeStack); GH.totalRedraw(); } void CBattleInterface::setPrintMouseShadow(bool set) { - curInt->sysOpts.printMouseShadow = set; - curInt->sysOpts.settingsChanged(); + Settings shadow = settings.write["battle"]["mouseShadow"]; + shadow->Bool() = set; } void CBattleInterface::activate() @@ -463,7 +465,7 @@ void CBattleInterface::activate() attackingHero->activate(); if(defendingHero) defendingHero->activate(); - if(curInt->sysOpts.showQueue) + if(settings["battle"]["showQueue"].Bool()) queue->activate(); if(tacticsMode) @@ -500,7 +502,7 @@ void CBattleInterface::deactivate() attackingHero->deactivate(); if(defendingHero) defendingHero->deactivate(); - if(curInt->sysOpts.showQueue) + if(settings["battle"]["showQueue"].Bool()) queue->deactivate(); if(tacticsMode) @@ -537,7 +539,7 @@ void CBattleInterface::show(SDL_Surface * to) { //showing background blitAt(background, pos.x, pos.y, to); - if(curInt->sysOpts.printCellBorders) + if(settings["battle"]["cellBorders"].Bool()) { CSDL_Ext::blit8bppAlphaTo24bpp(cellBorders, NULL, to, &pos); } @@ -574,7 +576,7 @@ void CBattleInterface::show(SDL_Surface * to) std::set shaded = spToCast.rangeInHexes(b, schoolLevel); for(std::set::iterator it = shaded.begin(); it != shaded.end(); ++it) //for spells with range greater then one hex { - if(curInt->sysOpts.printMouseShadow && (*it % GameConstants::BFIELD_WIDTH != 0) && (*it % GameConstants::BFIELD_WIDTH != 16)) + if(settings["battle"]["mouseShadow"].Bool() && (*it % GameConstants::BFIELD_WIDTH != 0) && (*it % GameConstants::BFIELD_WIDTH != 16)) { int x = 14 + ((*it/GameConstants::BFIELD_WIDTH)%2==0 ? 22 : 0) + 44*(*it%GameConstants::BFIELD_WIDTH) + pos.x; int y = 86 + 42 * (*it/GameConstants::BFIELD_WIDTH) + pos.y; @@ -583,7 +585,7 @@ void CBattleInterface::show(SDL_Surface * to) } } } - else if(curInt->sysOpts.printMouseShadow) //when not casting spell + else if(settings["battle"]["mouseShadow"].Bool()) //when not casting spell {//TODO: do not check it every frame if (activeStack) //highlight all attackable hexes { @@ -830,7 +832,7 @@ void CBattleInterface::show(SDL_Surface * to) Rect posWithQueue = Rect(pos.x, pos.y, 800, 600); - if(curInt->sysOpts.showQueue) + if(settings["battle"]["showQueue"].Bool()) { if(!queue->embedded) { @@ -886,7 +888,7 @@ void CBattleInterface::showObstacles(std::multimap *hexToObstacl int x = ((curOb.pos/GameConstants::BFIELD_WIDTH)%2==0 ? 22 : 0) + 44*(curOb.pos%GameConstants::BFIELD_WIDTH) + pos.x + shift.first; int y = 86 + 42 * (curOb.pos/GameConstants::BFIELD_WIDTH) + pos.y + shift.second; std::vector &images = idToObstacle[curOb.ID]->ourImages; //reference to animation of obstacle - blitAt(images[((animCount+1)/(4/curInt->sysOpts.animSpeed))%images.size()].bitmap, x, y, to); + blitAt(images[((animCount+1)/(4/getAnimSpeed()))%images.size()].bitmap, x, y, to); } } @@ -894,12 +896,11 @@ void CBattleInterface::keyPressed(const SDL_KeyboardEvent & key) { if(key.keysym.sym == SDLK_q && key.state == SDL_PRESSED) { - if(curInt->sysOpts.showQueue) //hide queue + if(settings["battle"]["showQueue"].Bool()) //hide queue hideQueue(); else showQueue(); - curInt->sysOpts.settingsChanged(); } else if(key.keysym.sym == SDLK_ESCAPE && spellDestSelectMode) { @@ -1459,7 +1460,7 @@ void CBattleInterface::bSpellf() chi = attackingHeroInstance; else chi = defendingHeroInstance; - CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (conf.cc.resx - 620)/2, (conf.cc.resy - 595)/2), chi, curInt); + CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), chi, curInt); GH.pushInt(spellWindow); } @@ -2470,13 +2471,13 @@ void CBattleInterface::battleTriggerEffect(const BattleTriggerEffect & bte) void CBattleInterface::setAnimSpeed(int set) { - curInt->sysOpts.animSpeed = set; - curInt->sysOpts.settingsChanged(); + Settings speed = settings.write["battle"]["animationSpeed"]; + speed->Float() = set; } int CBattleInterface::getAnimSpeed() const { - return curInt->sysOpts.animSpeed; + return settings["battle"]["animationSpeed"].Float(); } void CBattleInterface::activateStack() @@ -2519,7 +2520,7 @@ void CBattleInterface::activateStack() double CBattleInterface::getAnimSpeedMultiplier() const { - switch(curInt->sysOpts.animSpeed) + switch(getAnimSpeed()) { case 1: return 3.5; @@ -2552,7 +2553,7 @@ void CBattleInterface::showAliveStack(const CStack *stack, SDL_Surface * to) int animType = creAnims[ID]->getType(); - int affectingSpeed = curInt->sysOpts.animSpeed; + int affectingSpeed = getAnimSpeed(); if(animType == 1 || animType == 2) //standing stacks should not stand faster :) affectingSpeed = 2; bool incrementFrame = (animCount%(4/affectingSpeed)==0) && animType!=5 && animType!=20 && animType!=2; @@ -2744,13 +2745,13 @@ void CBattleInterface::redrawBackgroundWithHexes(const CStack * activeStack) attackableHexes.clear(); if (activeStack) occupyableHexes = curInt->cb->battleGetAvailableHexes(activeStack, true, &attackableHexes); - curInt->cb->battleGetStackCountOutsideHexes(stackCountOutsideHexes); + curInt->cb->battleGetStackCountOutsideHexes(stackCountOutsideHexes); //preparating background graphic with hexes and shaded hexes blitAt(background, 0, 0, backgroundWithHexes); - if(curInt->sysOpts.printCellBorders) + if(settings["battle"]["cellBorders"].Bool()) CSDL_Ext::blit8bppAlphaTo24bpp(cellBorders, NULL, backgroundWithHexes, NULL); - if(curInt->sysOpts.printStackRange) + if(settings["battle"]["stackRange"].Bool()) { std::vector hexesToShade = occupyableHexes; hexesToShade.insert(hexesToShade.end(), attackableHexes.begin(), attackableHexes.end()); @@ -2914,7 +2915,8 @@ void CBattleInterface::endAction(const BattleAction* action) void CBattleInterface::hideQueue() { - curInt->sysOpts.showQueue = false; + Settings showQueue = settings.write["battle"]["showQueue"]; + showQueue->Bool() = false; queue->deactivate(); @@ -2927,7 +2929,8 @@ void CBattleInterface::hideQueue() void CBattleInterface::showQueue() { - curInt->sysOpts.showQueue = true; + Settings showQueue = settings.write["battle"]["showQueue"]; + showQueue->Bool() = true; queue->activate(); diff --git a/client/BattleInterface/CBattleInterfaceClasses.cpp b/client/BattleInterface/CBattleInterfaceClasses.cpp index 04c105a1d..8bbbe7d6b 100644 --- a/client/BattleInterface/CBattleInterfaceClasses.cpp +++ b/client/BattleInterface/CBattleInterfaceClasses.cpp @@ -204,7 +204,7 @@ void CBattleHero::clickLeft(tribool down, bool previousState) } CCS->curh->changeGraphic(0,0); - CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (conf.cc.resx - 620)/2, (conf.cc.resy - 595)/2), myHero, myOwner->curInt); + CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, myOwner->curInt); GH.pushInt(spellWindow); } } @@ -250,11 +250,11 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt background->colorize(owner->curInt->playerID); viewGrid = new CHighlightableButton(boost::bind(&CBattleInterface::setPrintCellBorders, owner, true), boost::bind(&CBattleInterface::setPrintCellBorders, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[427].first)(3,CGI->generaltexth->zelp[427].first), CGI->generaltexth->zelp[427].second, false, "sysopchk.def", NULL, 25, 56, false); - viewGrid->select(owner->curInt->sysOpts.printCellBorders); + viewGrid->select(settings["battle"]["cellBorders"].Bool()); movementShadow = new CHighlightableButton(boost::bind(&CBattleInterface::setPrintStackRange, owner, true), boost::bind(&CBattleInterface::setPrintStackRange, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[428].first)(3,CGI->generaltexth->zelp[428].first), CGI->generaltexth->zelp[428].second, false, "sysopchk.def", NULL, 25, 89, false); - movementShadow->select(owner->curInt->sysOpts.printStackRange); + movementShadow->select(settings["battle"]["stackRange"].Bool()); mouseShadow = new CHighlightableButton(boost::bind(&CBattleInterface::setPrintMouseShadow, owner, true), boost::bind(&CBattleInterface::setPrintMouseShadow, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[429].first)(3,CGI->generaltexth->zelp[429].first), CGI->generaltexth->zelp[429].second, false, "sysopchk.def", NULL, 25, 122, false); - mouseShadow->select(owner->curInt->sysOpts.printMouseShadow); + mouseShadow->select(settings["battle"]["mouseShadow"].Bool()); animSpeeds = new CHighlightableButtonsGroup(0); animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[422].first),CGI->generaltexth->zelp[422].second, "sysopb9.def", 28, 225, 1); diff --git a/client/CAdvmapInterface.cpp b/client/CAdvmapInterface.cpp index d4ef03abe..e748a27f8 100644 --- a/client/CAdvmapInterface.cpp +++ b/client/CAdvmapInterface.cpp @@ -350,11 +350,11 @@ void CMinimapSurfacesRef::free() for (int g = 0; g < map_.size(); ++g) SDL_FreeSurface(map_[g]); map_.clear(); - + for (int g = 0; g < FoW_.size(); ++g) SDL_FreeSurface(FoW_[g]); FoW_.clear(); - + for (int g = 0; g < flObjs_.size(); ++g) SDL_FreeSurface(flObjs_[g]); flObjs_.clear(); @@ -396,7 +396,7 @@ void CMinimap::showTile(const int3 &pos) { int3 maplgp ( (pos.x*mw)/mapSizes.x, (pos.y*mh)/mapSizes.y, pos.z ); if(((int)wo) * mapSizes.x != mw && pos.x+1 < mapSizes.x)//minimap size in X is not multiple of map size in X - + { std::vector < const CGObjectInstance * > op1x = LOCPLINT->cb->getFlaggableObjects(int3(pos.x+1, pos.y, pos.z)); if(op1x.size()!=0) @@ -588,7 +588,7 @@ void CTerrainRect::showPath(const SDL_Rect * extRect, SDL_Surface * to) /* Vector directions * 0 1 2 - * \ | / + * \ | / * 3 - 4 - 5 * / | \ * 6 7 8 @@ -597,7 +597,7 @@ void CTerrainRect::showPath(const SDL_Rect * extRect, SDL_Surface * to) * |__\ * / * is id1=7, id2=5 (pns[7][5]) - */ + */ bool pathContinuous = curPos.areNeighbours(nextPos) && curPos.areNeighbours(prevPos); if(pathContinuous && cv[i].land == cv[i+1].land) { @@ -695,7 +695,7 @@ void CTerrainRect::show(SDL_Surface * to) (adventureInt->position, adventureInt->anim, &LOCPLINT->cb->getVisibilityMap(), true, adventureInt->heroAnim, to, &pos, 0, 0, false, int3()); - + //SDL_BlitSurface(teren,&genRect(pos.h,pos.w,0,0),screen,&genRect(547,594,7,6)); //SDL_FreeSurface(teren); if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path @@ -742,7 +742,7 @@ CResDataBar::CResDataBar(const std::string &defname, int x, int y, int offx, int txtpos[i].second = pos.y + offy; } txtpos[7].first = txtpos[6].first + datedist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; } CResDataBar::CResDataBar() @@ -759,7 +759,7 @@ CResDataBar::CResDataBar() txtpos[i].second = pos.y + ADVOPT.resOffsetY; } txtpos[7].first = txtpos[6].first + ADVOPT.resDateDist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; } @@ -1098,14 +1098,14 @@ void CAdvMapInt::fsleepWake() { fnextHero(); - //moveHero.block(true); + //moveHero.block(true); //uncomment to enable original HoMM3 behaviour: //move button is disabled for hero going to sleep, even though it's enabled when you reselect him } } void CAdvMapInt::fmoveHero() -{ +{ const CGHeroInstance *h = curHero(); if (!h || !terrain.currentPath) return; @@ -1119,7 +1119,8 @@ void CAdvMapInt::fshowSpellbok() return; centerOn(selection); - CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (conf.cc.resx - 620)/2, (conf.cc.resy - 595)/2), curHero(), LOCPLINT, false); + + CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), curHero(), LOCPLINT, false); GH.pushInt(spellWindow); } @@ -1147,12 +1148,15 @@ void CAdvMapInt::fendTurn() if(!LOCPLINT->makingTurn) return; - for (int i = 0; i < LOCPLINT->wanderingHeroes.size(); i++) - if (!isHeroSleeping(LOCPLINT->wanderingHeroes[i]) && (LOCPLINT->wanderingHeroes[i]->movement > 0)) - { - LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::vector(), boost::bind(&CAdvMapInt::endingTurn, this), 0, false); - return; - } + if ( settings["adventure"]["heroReminder"].Bool()) + { + for (int i = 0; i < LOCPLINT->wanderingHeroes.size(); i++) + if (!isHeroSleeping(LOCPLINT->wanderingHeroes[i]) && (LOCPLINT->wanderingHeroes[i]->movement > 0)) + { + LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::vector(), boost::bind(&CAdvMapInt::endingTurn, this), 0, false); + return; + } + } endingTurn(); } @@ -1160,7 +1164,7 @@ void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) { sleepWake.block(!h); if (!h) - return; + return; bool state = isHeroSleeping(h); sleepWake.setIndex(state ? 1 : 0, true); sleepWake.assignedKeys.clear(); @@ -1171,11 +1175,11 @@ void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) { //default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately - if (hasPath == tribool::indeterminate_value) + if (hasPath == tribool::indeterminate_value) hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; if (!h) { - moveHero.block(true); + moveHero.block(true); return; } moveHero.block(!hasPath || (h->movement == 0)); @@ -1188,12 +1192,12 @@ int CAdvMapInt::getNextHeroIndex(int startIndex) if (startIndex < 0) startIndex = 0; int i = startIndex; - do + do { i++; if (i >= LOCPLINT->wanderingHeroes.size()) i = 0; - } + } while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex)); if ((LOCPLINT->wanderingHeroes[i]->movement != 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i])) @@ -1204,7 +1208,7 @@ int CAdvMapInt::getNextHeroIndex(int startIndex) void CAdvMapInt::updateNextHero(const CGHeroInstance *h) { - int start = heroList.getPosOfHero(h); + int start = heroList.getPosOfHero(h); int next = getNextHeroIndex(start); if (next < 0) { @@ -1338,11 +1342,12 @@ void CAdvMapInt::show(SDL_Surface * to) } ++heroAnim; + int scrollSpeed = settings["adventure"]["scrollSpeed"].Float(); //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) - if((animValHitCount % (4/LOCPLINT->sysOpts.mapScrollingSpeed)) == 0 + if((animValHitCount % (4/scrollSpeed)) == 0 && ( (GH.topInt() == this) - || SDL_GetKeyState(NULL)[SDLK_LCTRL] + || SDL_GetKeyState(NULL)[SDLK_LCTRL] || SDL_GetKeyState(NULL)[SDLK_RCTRL] ) ) @@ -1370,7 +1375,7 @@ void CAdvMapInt::show(SDL_Surface * to) terrain.show(to); for(int i=0;i<4;i++) blitAt(gems[i]->ourImages[LOCPLINT->playerID].bitmap,ADVOPT.gemX[i],ADVOPT.gemY[i],to); - updateScreen=false; + updateScreen=false; LOCPLINT->cingconsole->show(to); } if (updateMinimap) @@ -1389,13 +1394,13 @@ void CAdvMapInt::centerOn(int3 on) { on.x -= CGI->mh->frameW; on.y -= CGI->mh->frameH; - + on = LOCPLINT->repairScreenPos(on); adventureInt->position = on; adventureInt->updateScreen=true; updateMinimap=true; - underground.setIndex(on.z,true); //change underground switch button image + underground.setIndex(on.z,true); //change underground switch button image if(GH.topInt() == this) underground.redraw(); } @@ -1415,27 +1420,27 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) switch(k) { - case SDLK_i: + case SDLK_i: if(isActive()) CAdventureOptions::showScenarioInfo(); return; - case SDLK_s: + case SDLK_s: if(isActive()) GH.pushInt(new CSavingScreen(CPlayerInterface::howManyPeople > 1)); return; - case SDLK_d: + case SDLK_d: { if(h && isActive() && key.state == SDL_PRESSED) LOCPLINT->tryDiggging(h); return; } - case SDLK_p: + case SDLK_p: if(isActive()) LOCPLINT->showPuzzleMap(); return; case SDLK_SPACE: //space - try to revisit current object with selected hero { - if(!isActive()) + if(!isActive()) return; if(h && key.state == SDL_PRESSED) { @@ -1447,7 +1452,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) return; case SDLK_RETURN: { - if(!isActive() || !selection || key.state != SDL_PRESSED) + if(!isActive() || !selection || key.state != SDL_PRESSED) return; if(h) LOCPLINT->openHeroWindow(h); @@ -1457,7 +1462,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) } case SDLK_ESCAPE: { - if(isActive() || GH.topInt() != this || !spellBeingCasted || key.state != SDL_PRESSED) + if(isActive() || GH.topInt() != this || !spellBeingCasted || key.state != SDL_PRESSED) return; leaveCastingMode(); @@ -1480,12 +1485,12 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) } if(townWithMarket) //if any town has marketplace, open window - GH.pushInt(new CMarketplaceWindow(townWithMarket)); + GH.pushInt(new CMarketplaceWindow(townWithMarket)); else //if not - complain LOCPLINT->showInfoDialog("No available marketplace!", std::vector(), soundBase::sound_todo); return; } - default: + default: { static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0), int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0), @@ -1496,16 +1501,16 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) { switch(k) { - case SDLK_UP: + case SDLK_UP: Dir = UP; break; - case SDLK_LEFT: + case SDLK_LEFT: Dir = LEFT; break; - case SDLK_RIGHT: + case SDLK_RIGHT: Dir = RIGHT; break; - case SDLK_DOWN: + case SDLK_DOWN: Dir = DOWN; break; } @@ -1520,7 +1525,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) if(k < 0 || k > 8 || key.state != SDL_PRESSED) return; - if(!h) + if(!h) break; if(k == 4) @@ -1720,7 +1725,7 @@ void CAdvMapInt::tileLClicked(const int3 &mp) switch(spellBeingCasted->id) { - case Spells::SCUTTLE_BOAT: //Scuttle Boat + case Spells::SCUTTLE_BOAT: //Scuttle Boat if(topBlocking && topBlocking->ID == 8) leaveCastingMode(true, mp); break; @@ -1769,7 +1774,7 @@ void CAdvMapInt::tileLClicked(const int3 &mp) CGPath &path = LOCPLINT->paths[currentHero]; terrain.currentPath = &path; bool gotPath = LOCPLINT->cb->getPath2(mp, path); //try getting path, erase if failed - updateMoveHero(currentHero); + updateMoveHero(currentHero); if (!gotPath) LOCPLINT->eraseCurrentPathOf(currentHero); else @@ -1811,7 +1816,7 @@ void CAdvMapInt::tileHovered(const int3 &tile) } const CGPathNode *pnode = LOCPLINT->cb->getPathInfo(tile); - std::vector objs = LOCPLINT->cb->getBlockingObjs(tile); + std::vector objs = LOCPLINT->cb->getBlockingObjs(tile); const CGObjectInstance *objAtTile = objs.size() ? objs.back() : NULL; bool accessible = pnode->turns < 255; @@ -1885,7 +1890,7 @@ void CAdvMapInt::tileHovered(const int3 &tile) { if(!LOCPLINT->cb->getPlayerRelations( LOCPLINT->playerID, objAtTile->tempOwner)) //enemy town { - if(accessible) + if(accessible) { const CGTownInstance* townObj = dynamic_cast(objAtTile); @@ -1895,8 +1900,8 @@ void CAdvMapInt::tileHovered(const int3 &tile) else CCS->curh->changeGraphic(0, 5 + turns*6); - } - else + } + else { CCS->curh->changeGraphic(0, 0); } @@ -1918,18 +1923,18 @@ void CAdvMapInt::tileHovered(const int3 &tile) } else if (objAtTile->ID == 33 || objAtTile->ID == 219) // Garrison { - if (accessible) + if (accessible) { const CGGarrison* garrObj = dynamic_cast(objAtTile); //TODO evil evil cast! // Show battle cursor for guarded enemy garrisons, otherwise movement cursor. - if (garrObj && garrObj->stacksCount() + if (garrObj && garrObj->stacksCount() && !LOCPLINT->cb->getPlayerRelations( LOCPLINT->playerID, garrObj->tempOwner) ) CCS->curh->changeGraphic(0, 5 + turns*6); else CCS->curh->changeGraphic(0, 9 + turns*6); - } - else + } + else CCS->curh->changeGraphic(0, 0); } else if (guardingCreature && accessible) //(objAtTile->ID == 54) //monster @@ -1948,15 +1953,15 @@ void CAdvMapInt::tileHovered(const int3 &tile) else CCS->curh->changeGraphic(0, 0); } - } - else //no objs + } + else //no objs { if(accessible/* && pnode->accessible != CGPathNode::FLYABLE*/) { - if (guardingCreature) + if (guardingCreature) { CCS->curh->changeGraphic(0, 5 + turns*6); - } else + } else { if(pnode->land) { @@ -1994,11 +1999,11 @@ void CAdvMapInt::tileRClicked(const int3 &mp) } std::vector < const CGObjectInstance * > objs = LOCPLINT->cb->getBlockingObjs(mp); - if(!objs.size()) + if(!objs.size()) { // Bare or undiscovered terrain const TerrainTile * tile = LOCPLINT->cb->getTile(mp); - if (tile) + if (tile) { std::string hlp; CGI->mh->getTerrainDescr(mp, hlp, true); @@ -2032,7 +2037,7 @@ void CAdvMapInt::leaveCastingMode(bool cast /*= false*/, int3 dest /*= int3(-1, if(cast) LOCPLINT->cb->castSpell(curHero(), id, dest); - else + else LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled } diff --git a/client/CConfigHandler.cpp b/client/CConfigHandler.cpp index f83ef38cc..85231acbb 100644 --- a/client/CConfigHandler.cpp +++ b/client/CConfigHandler.cpp @@ -1,22 +1,11 @@ -#include "StdInc.h" -#include +#include "StdInc.h" #include "CConfigHandler.h" -#include "../lib/JsonNode.h" -#include "../lib/GameConstants.h" +#include "../lib/GameConstants.h" +#include "../lib/VCMIDirs.h" using namespace config; -#if BOOST_VERSION >= 103800 -#include -using namespace boost::spirit::classic; -#else -#include -using namespace boost::spirit; -#endif - -using namespace phoenix; - /* * CConfigHandler.cpp, part of VCMI engine * @@ -26,91 +15,150 @@ using namespace phoenix; * Full text of license available in license.txt file, in main folder * */ - + +SettingsStorage settings; CConfigHandler conf; - -struct lerror + +template +SettingsStorage::NodeAccessor::NodeAccessor(SettingsStorage & _parent, std::vector _path): + parent(_parent), + path(_path) { - std::string txt; - lerror(const std::string & TXT):txt(TXT){}; - void operator()() const - { - tlog1 << txt << std::endl; - } - template - void operator()(IteratorT t1, IteratorT t2) const - { - tlog1 << txt << std::endl; - } -}; - -struct lerror2 +} + +template +SettingsStorage::NodeAccessor SettingsStorage::NodeAccessor::operator [](std::string nextNode) const { - std::string txt; - lerror2(const std::string & TXT):txt(TXT){}; - template - void operator()(IteratorT t1, IteratorT t2) const - { - std::string txt2(t1,t2); - tlog1 << txt << txt2 << std::endl; - } -}; - -struct SettingsGrammar : public grammar + std::vector newPath = path; + newPath.push_back(nextNode); + return NodeAccessor(parent, newPath); +} + +template +SettingsStorage::NodeAccessor::operator Accessor() const { - template - struct definition - { - rule r, clientOption, clientOptionsSequence, ClientSettings; + return Accessor(parent, path); +} + +template +SettingsStorage::NodeAccessor SettingsStorage::NodeAccessor::operator () (std::vector _path) +{ + std::vector newPath = path; + newPath.insert( newPath.end(), _path.begin(), _path.end()); + return NodeAccessor(parent, newPath); +} - definition(SettingsGrammar const& self) - { - clientOption - = str_p("resolution=") >> (uint_p[assign_a(conf.cc.resx)] >> 'x' >> uint_p[assign_a(conf.cc.resy)] | eps_p[lerror("Wrong resolution!")]) - | str_p("pregameRes=") >> (uint_p[assign_a(conf.cc.pregameResx)] >> 'x' >> uint_p[assign_a(conf.cc.pregameResy)] | eps_p[lerror("Wrong pregame size!")]) - | str_p("screenSize=") >> (uint_p[assign_a(conf.cc.screenx)] >> 'x' >> uint_p[assign_a(conf.cc.screeny)] | eps_p[lerror("Wrong screen size!")]) - | str_p("port=") >> (uint_p[assign_a(conf.cc.port)] | eps_p[lerror("Wrong port!")]) - | str_p("bpp=") >> (uint_p[assign_a(conf.cc.bpp)] | eps_p[lerror("Wrong bpp!")]) - | str_p("localInformation=") >> (uint_p[assign_a(conf.cc.localInformation)] | eps_p[lerror("Wrong localInformation!")]) - | str_p("fullscreen=") >> (uint_p[assign_a(conf.cc.fullscreen)] | eps_p[lerror("Wrong fullscreen!")]) - | str_p("server=") >> ( ( +digit_p >> *('.' >> +digit_p) )[assign_a(conf.cc.server)] | eps_p[lerror("Wrong server!")]) - | str_p("defaultPlayerAI=") >> ((+(anychar_p - ';'))[assign_a(conf.cc.defaultPlayerAI)] | eps_p[lerror("Wrong defaultAI!")]) - | str_p("neutralBattleAI=") >> ((+(anychar_p - ';'))[assign_a(conf.cc.defaultBattleAI)] | eps_p[lerror("Wrong defaultAI!")]) - | str_p("showFPS=") >> (uint_p[assign_a(conf.cc.showFPS)] | eps_p[lerror("Wrong showFPS!")]) - | str_p("classicCreatureWindow=") >> (uint_p[assign_a(conf.cc.classicCreatureWindow)] | eps_p[lerror("Wrong classicCreatureWindow!")]) - | (+(anychar_p - '}'))[lerror2("Unrecognized client option: ")] - ; - clientOptionsSequence = *(clientOption >> (';' | eps_p[lerror("Semicolon lacking after client option!")])); - ClientSettings = '{' >> clientOptionsSequence >> '}'; - - r = str_p("clientSettings") >> (ClientSettings | eps_p[lerror("Wrong clientSettings!")]); - -#ifdef BOOST_SPIRIT_DEBUG - BOOST_SPIRIT_DEBUG_RULE(clientOption); - BOOST_SPIRIT_DEBUG_RULE(clientOptionsSequence); - BOOST_SPIRIT_DEBUG_RULE(ClientSettings); - BOOST_SPIRIT_DEBUG_RULE(r); -#endif - } - - rule const& start() const { return r; } - }; -}; - -struct CommentsGrammar : public grammar +SettingsStorage::SettingsStorage(): + write(NodeAccessor(*this, std::vector() )), + listen(NodeAccessor(*this, std::vector() )) { - template - struct definition - { - rule comment; - definition(CommentsGrammar const& self) - { - comment = comment_p("//") | comment_p("/*","*/") | space_p; - BOOST_SPIRIT_DEBUG_RULE(comment); - } - rule const& start() const { return comment; } - }; -}; +} + +void SettingsStorage::init() +{ + JsonNode(GVCMIDirs.UserPath + "/config/settings.json").swap(config); + JsonNode schema(GameConstants::DATA_DIR + "/config/defaultSettings.json"); + config.validate(schema); +} + +void SettingsStorage::invalidateNode(const std::vector &changedPath) +{ + BOOST_FOREACH(SettingsListener * listener, listeners) + listener->nodeInvalidated(changedPath); + + JsonNode savedConf = config; + JsonNode schema(GameConstants::DATA_DIR + "/config/defaultSettings.json"); + + savedConf.Struct().erase("session"); + savedConf.minimize(schema); + std::ofstream file((GVCMIDirs.UserPath + "/config/settings.json").c_str(), std::ofstream::trunc | std::ofstream::out); + file << savedConf; +} + +JsonNode & SettingsStorage::getNode(std::vector path) +{ + JsonNode *node = &config; + BOOST_FOREACH(std::string& value, path) + node = &(*node)[value]; + + return *node; +} + +Settings SettingsStorage::get(std::vector path) +{ + return Settings(*this, path); +} + +const JsonNode& SettingsStorage::operator [](std::string value) +{ + return config[value]; +} + +SettingsListener::SettingsListener(SettingsStorage &_parent, const std::vector &_path): + parent(_parent), + path(_path) +{ + parent.listeners.insert(this); +} + +SettingsListener::~SettingsListener() +{ + parent.listeners.erase(this); +} + +void SettingsListener::nodeInvalidated(const std::vector changedPath) +{ + if (!callback) + return; + + size_t min = std::min(path.size(), changedPath.size()); + size_t mismatch = std::mismatch(path.begin(), path.begin()+min, changedPath.begin()).first - path.begin(); + + if (min == mismatch) + callback(parent.getNode(path)); +} + +void SettingsListener::operator() (boost::function _callback) +{ + callback = _callback; +} + +Settings::Settings(SettingsStorage &_parent, const std::vector &_path): + parent(_parent), + path(_path), + node(_parent.getNode(_path)), + copy(_parent.getNode(_path)) +{ +} + +Settings::~Settings() +{ + if (node != copy) + parent.invalidateNode(path); +} + +JsonNode* Settings::operator -> () +{ + return &node; +} + +const JsonNode* Settings::operator ->() const +{ + return &node; +} + +const JsonNode& Settings::operator [](std::string value) const +{ + return node[value]; +} + +JsonNode& Settings::operator [](std::string value) +{ + return node[value]; +} + +template struct SettingsStorage::NodeAccessor; +template struct SettingsStorage::NodeAccessor; static void setButton(ButtonInfo &button, const JsonNode &g) { @@ -145,29 +193,6 @@ CConfigHandler::~CConfigHandler(void) void config::CConfigHandler::init() { - std::vector settings; - std::string settingsDir = GameConstants::DATA_DIR + "/config/settings.txt"; - std::ifstream ifs(settingsDir.c_str()); - if(!ifs) - { - tlog1 << "Cannot open " << GameConstants::DATA_DIR << "/config/settings.txt !" << std::endl; - return; - } - ifs.unsetf(std::ios::skipws); // Turn of white space skipping on the stream - std::copy(std::istream_iterator(ifs),std::istream_iterator(),std::back_inserter(settings)); - std::vector::const_iterator first = settings.begin(), last = settings.end(); - SettingsGrammar sg; - BOOST_SPIRIT_DEBUG_NODE(sg); - CommentsGrammar cg; - BOOST_SPIRIT_DEBUG_NODE(cg); - - - parse_info::const_iterator> info = parse(first,last,sg,cg); - if(!info.hit) - tlog1 << "Cannot parse config/settings.txt file!\n"; - else if(!info.full) - tlog2 << "Not entire config/settings.txt parsed!\n"; - /* Read resolutions. */ const JsonNode config(GameConstants::DATA_DIR + "/config/resolutions.json"); const JsonVector &guisettings_vec = config["GUISettings"].Vector(); @@ -244,13 +269,16 @@ void config::CConfigHandler::init() setButton(current->ac.endTurn, g["ButtonEndTurn"]); } - //fixing screenx / screeny if set to 0x0 - if (cc.screenx == 0 && cc.screeny == 0) + const JsonNode& screenRes = settings["video"]["screenRes"]; + const JsonNode& gameRes = settings["video"]["gameRes"]; + + //fixing screenx / screeny + if (screenRes["width"].Float() != gameRes["width"].Float() + || screenRes["height"].Float() != gameRes["height"].Float()) { - cc.screenx = cc.resx; - cc.screeny = cc.resy; + Settings screen = settings.write["video"]["screenRes"]; + screen["width"].Float() = gameRes["width"].Float(); + screen["height"].Float() = gameRes["height"].Float(); } - cc.autoSkip = false; - cc.oneGoodAI = false; - SetResolution(cc.resx, cc.resy); + SetResolution(gameRes["width"].Float(), gameRes["height"].Float()); } diff --git a/client/CConfigHandler.h b/client/CConfigHandler.h index ecc3a189d..ed6dbd91f 100644 --- a/client/CConfigHandler.h +++ b/client/CConfigHandler.h @@ -1,8 +1,6 @@ #pragma once - - -class CAdvMapInt; +#include "../lib/JsonNode.h" /* * CConfighandler.h, part of VCMI engine @@ -14,22 +12,103 @@ class CAdvMapInt; * */ +class Settings; +class SettingsListener; + +/// Main storage of game settings +class SettingsStorage +{ + //Helper struct to access specific node either via chain of operator[] or with one operator() (vector) + template + struct NodeAccessor + { + SettingsStorage & parent; + std::vector path; + + NodeAccessor(SettingsStorage & _parent, std::vector _path); + NodeAccessor operator [] (std::string nextNode) const; + NodeAccessor operator () (std::vector _path); + operator Accessor() const; + }; + + std::set listeners; + JsonNode config; + JsonNode & getNode(std::vector path); + + // Calls all required listeners + void invalidateNode(const std::vector &changedPath); + + Settings get(std::vector path); +public: + // Initialize config structure + SettingsStorage(); + void init(); + + // Get write access to config node at path + const NodeAccessor write; + + // Get access to listener at path + const NodeAccessor listen; + + //Read access, see JsonNode::operator[] + const JsonNode& operator [](std::string value); + + friend class SettingsListener; + friend class Settings; +}; + +/// Class for listening changes in specific part of configuration (e.g. change of music volume) +class SettingsListener +{ + SettingsStorage &parent; + // Path to this node + std::vector path; + // Callback + boost::function callback; + + SettingsListener(SettingsStorage &_parent, const std::vector &_path); + + // Executes callback if changedpath begins with path + void nodeInvalidated(const std::vector changedPath); + +public: + ~SettingsListener(); + + // assign callback function + void operator()(boost::function _callback); + + friend class SettingsStorage; +}; + +/// System options, provides write access to config tree with auto-saving on change +class Settings +{ + SettingsStorage &parent; + //path to this node + std::vector path; + JsonNode &node; + JsonNode copy; + + //Get access to node pointed by path + Settings(SettingsStorage &_parent, const std::vector &_path); + +public: + //Saves config if it was modified + ~Settings(); + + //Returns node selected during construction + JsonNode* operator ->(); + const JsonNode* operator ->() const; + + //Helper, replaces JsonNode::operator[] + JsonNode& operator [](std::string value); + const JsonNode& operator [](std::string value) const; + + friend class SettingsStorage; +}; + namespace config { - /// Struct holds data about client resolution, colors, fullscreen mode - struct ClientConfig - { - int resx, resy, bpp, fullscreen; //client resolution/colours - int screenx, screeny; //real screen resolution - int pregameResx, pregameResy; //real screen resolution of preGame - int port, localInformation; - std::string server, //server address (e.g. 127.0.0.1) - defaultPlayerAI, defaultBattleAI; //dll names - bool showFPS; //show/hide FPS counter - bool classicCreatureWindow; - bool autoSkip, oneGoodAI; //for AI testing purposes - }; - struct ButtonInfo { std::string defName; @@ -84,8 +163,8 @@ namespace config GUIOptions *current; // pointer to current gui options public: - ClientConfig cc; - std::map, GUIOptions > guiOptions; + typedef std::map, GUIOptions > GuiOptionsMap; + GuiOptionsMap guiOptions; void init(); CConfigHandler(void); //c-tor ~CConfigHandler(void); //d-tor @@ -96,4 +175,6 @@ namespace config } }; } + +extern SettingsStorage settings; extern config::CConfigHandler conf; diff --git a/client/CCreatureWindow.cpp b/client/CCreatureWindow.cpp index d217666e4..278bf356a 100644 --- a/client/CCreatureWindow.cpp +++ b/client/CCreatureWindow.cpp @@ -177,7 +177,7 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode * bonusItems.push_back (new CBonusItem(genRect(0, 0, 251, 57), text, description, stack->bonusToGraphics(&b))); } - bonusRows = std::min ((int)((bonusItems.size() + 1) / 2), (conf.cc.resy - 230) / 60); + bonusRows = std::min ((int)((bonusItems.size() + 1) / 2), (screen->h - 230) / 60); vstd::amin(bonusRows, 4); vstd::amax(bonusRows, 1); @@ -627,7 +627,7 @@ void CCreInfoWindow::clickRight(tribool down, bool previousState) CIntObject * createCreWindow(const CStack *s) { - if(conf.cc.classicCreatureWindow) + if(settings["general"]["classicCreatureWindow"].Bool()) return new CCreInfoWindow(*s); else return new CCreatureWindow(*s, CCreatureWindow::BATTLE); @@ -635,7 +635,7 @@ CIntObject * createCreWindow(const CStack *s) CIntObject * createCreWindow(int Cid, int Type, int creatureCount) { - if(conf.cc.classicCreatureWindow) + if(settings["general"]["classicCreatureWindow"].Bool()) return new CCreInfoWindow(Cid, Type, creatureCount); else return new CCreatureWindow(Cid, Type, creatureCount); @@ -643,7 +643,7 @@ CIntObject * createCreWindow(int Cid, int Type, int creatureCount) CIntObject * createCreWindow(const CStackInstance *s, int type, boost::function Upg, boost::function Dsm, UpgradeInfo *ui) { - if(conf.cc.classicCreatureWindow) + if(settings["general"]["classicCreatureWindow"].Bool()) return new CCreInfoWindow(*s, type==3, Upg, Dsm, ui); else return new CCreatureWindow(*s, type, Upg, Dsm, ui); diff --git a/client/CMT.cpp b/client/CMT.cpp index 386eb4a95..07412d0e2 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -64,12 +64,11 @@ std::string NAME_AFFIX = "client"; std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name CGuiHandler GH; static CClient *client; -SDL_Surface *screen = NULL, //main screen surface - *screen2 = NULL,//and hlp surface (used to store not-active interfaces layer) +SDL_Surface *screen = NULL, //main screen surface + *screen2 = NULL,//and hlp surface (used to store not-active interfaces layer) *screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed static boost::thread *mainGUIThread; -SystemOptions GDefaultOptions; VCMIDirs GVCMIDirs; std::queue events; boost::mutex eventsM; @@ -117,33 +116,16 @@ void init() #endif CSDL_Ext::std32bppSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, rmask, gmask, bmask, amask); tlog0 << "\tInitializing minors: " << pomtime.getDiff() << std::endl; - { - //read system options - CLoadFile settings(GVCMIDirs.UserPath + "/config/sysopts.bin", 727); - if(settings.sfile) - { - settings >> GDefaultOptions; - } - else //file not found (probably, may be also some kind of access problem - { - tlog2 << "Warning: Cannot read system options, default settings will be used.\n"; - - //Try to create file - tlog2 << "VCMI will try to save default system options...\n"; - GDefaultOptions.settingsChanged(); - } - } - tlog0 << "\tLoading default system settings: " << pomtime.getDiff() << std::endl; //initializing audio // Note: because of interface button range, volume can only be a // multiple of 11, from 0 to 99. CCS->soundh = new CSoundHandler; CCS->soundh->init(); - CCS->soundh->setVolume(GDefaultOptions.soundVolume); + CCS->soundh->setVolume(settings["general"]["sound"].Float()); CCS->musich = new CMusicHandler; CCS->musich->init(); - CCS->musich->setVolume(GDefaultOptions.musicVolume); + CCS->musich->setVolume(settings["general"]["music"].Float()); tlog0<<"\tInitializing sound: "<active ? "" : "not ") << "active\n"; + tlog4 << typeid(*obj).name() << " *** " << (obj->active ? "" : "not ") << "active"; + tlog4 << " at " << obj->pos.x <<"x"<< obj->pos.y << "\n"; BOOST_FOREACH(const CIntObject *child, obj->children) printInfoAboutIntObject(child, level+1); @@ -447,10 +436,13 @@ void processCommand(const std::string &message) else { for(j=conf.guiOptions.begin(); j!=conf.guiOptions.end() && hlp++first.first; - conf.cc.resy = conf.cc.screeny = j->first.second; - conf.SetResolution(conf.cc.screenx, conf.cc.screeny); - tlog0 << "Screen resolution set to " << conf.cc.screenx << " x " << conf.cc.screeny <<". It will be applied when the game starts.\n"; + Settings res = settings.write["video"]["gameRes"]; + Settings screen = settings.write["video"]["screenRes"]; + res["width"].Float() = res["width"].Float() = j->first.first; + screen["height"].Float() = screen["height"].Float() = j->first.second; + conf.SetResolution(screen["width"].Float(), screen["height"].Float()); + tlog0 << "Screen resolution set to " << (int)screen["width"].Float() << " x " + << (int)screen["height"].Float() <<". It will be applied when the game starts.\n"; } } else if(message=="get txt") @@ -460,7 +452,7 @@ void processCommand(const std::string &message) CLodHandler * txth = new CLodHandler; txth->init(GameConstants::DATA_DIR + "/Data/H3bitmap.lod",""); tlog0<<"done.\nScanning .lod file\n"; - + BOOST_FOREACH(Entry e, txth->entries) if( e.type == FILE_TEXT ) txth->extractFile(std::string(GVCMIDirs.UserPath + "/Extracted_txts/")+e.name, e.name, FILE_TEXT); @@ -532,7 +524,8 @@ void processCommand(const std::string &message) } else if (cn == "switchCreWin" ) { - conf.cc.classicCreatureWindow = !conf.cc.classicCreatureWindow; + Settings window = settings.write["general"]["classicCreatureWindow"]; + window->Bool() = !window->Bool(); } else if(cn == "sinfo") { @@ -574,7 +567,7 @@ void dispose() } static void setScreenRes(int w, int h, int bpp, bool fullscreen) -{ +{ // VCMI will only work with 2, 3 or 4 bytes per pixel vstd::amax(bpp, 16); vstd::amin(bpp, 32); @@ -674,7 +667,9 @@ static void listenForEvents() { boost::unique_lock lock(*LOCPLINT->pim); bool full = !(screen->flags&SDL_FULLSCREEN); - setScreenRes(conf.cc.screenx, conf.cc.screeny, conf.cc.bpp, full); + const JsonNode& video = settings["video"]; + const JsonNode& res = video["screenRes"]; + setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), full); GH.totalRedraw(); delete ev; continue; @@ -684,10 +679,13 @@ static void listenForEvents() switch(ev->user.code) { case 1: + { tlog0 << "Changing resolution has been requested\n"; - setScreenRes(conf.cc.screenx, conf.cc.screeny, conf.cc.bpp, conf.cc.fullscreen); + const JsonNode& video = settings["video"]; + const JsonNode& res = video["gameRes"]; + setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool()); break; - + } case 2: client->endGame(); delete client; @@ -718,20 +716,21 @@ static void listenForEvents() } } -void startGame(StartInfo * options, CConnection *serv/* = NULL*/) +void startGame(StartInfo * options, CConnection *serv/* = NULL*/) { GH.curInt =NULL; SDL_FillRect(screen, 0, 0); if(gOnlyAI) { - for(std::map::iterator it = options->playerInfos.begin(); + for(std::map::iterator it = options->playerInfos.begin(); it != options->playerInfos.end(); ++it) { it->second.human = false; } } + const JsonNode& res = settings["video"]["screenRes"]; - if(screen->w != conf.cc.screenx || screen->h != conf.cc.screeny) + if(screen->w != res["width"].Float() || screen->h != res["height"].Float()) { requestChangingResolution(); diff --git a/client/CMessage.cpp b/client/CMessage.cpp index 4a9178cdc..35508bee2 100644 --- a/client/CMessage.cpp +++ b/client/CMessage.cpp @@ -390,8 +390,8 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player) for(int i = 0; i < ARRAY_COUNT(sizes) - && sizes[i][0] < conf.cc.resx - 150 - && sizes[i][1] < conf.cc.resy - 150 + && sizes[i][0] < screen->w - 150 + && sizes[i][1] < screen->h - 150 && ret->text->slider; i++) { @@ -424,7 +424,7 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player) vstd::amax(winSize.first, comps.w); vstd::amax(winSize.first, bw); - vstd::amin(winSize.first, conf.cc.resx - 150); + vstd::amin(winSize.first, screen->w - 150); ret->bitmap = drawBox1 (winSize.first + 2*SIDE_MARGIN, winSize.second + 2*SIDE_MARGIN, player); ret->pos.h=ret->bitmap->h; diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index c5aec4b8d..c510a952e 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -66,8 +66,15 @@ void CAudioBase::setVolume(ui32 percent) volume = percent; } -CSoundHandler::CSoundHandler() +void CSoundHandler::onVolumeChange(const JsonNode &volumeNode) { + setVolume(volumeNode.Float()); +} + +CSoundHandler::CSoundHandler(): + listener(settings.listen["general"]["sound"]) +{ + listener(boost::bind(&CSoundHandler::onVolumeChange, this, _1)); // Map sound names #define VCMI_SOUND_NAME(x) ( soundBase::x, #define VCMI_SOUND_FILE(y) #y ) @@ -311,8 +318,15 @@ void CSoundHandler::soundFinishedCallback(int channel) callbacks.erase(iter); } -CMusicHandler::CMusicHandler() +void CMusicHandler::onVolumeChange(const JsonNode &volumeNode) { + setVolume(volumeNode.Float()); +} + +CMusicHandler::CMusicHandler(): + listener(settings.listen["general"]["music"]) +{ + listener(boost::bind(&CMusicHandler::onVolumeChange, this, _1)); // Map music IDs #define VCMI_MUSIC_ID(x) ( musicBase::x , #define VCMI_MUSIC_FILE(y) y ) diff --git a/client/CMusicHandler.h b/client/CMusicHandler.h index 9da4b851f..6958352af 100644 --- a/client/CMusicHandler.h +++ b/client/CMusicHandler.h @@ -1,5 +1,6 @@ #pragma once +#include "CConfigHandler.h" #include "CSoundBase.h" #include "CMusicBase.h" #include "../lib/CCreatureHandler.h" @@ -65,6 +66,9 @@ class CSoundHandler: public CAudioBase private: CSndHandler sndh; soundBase::soundID getSoundID(const std::string &fileName); + //update volume on configuration change + SettingsListener listener; + void onVolumeChange(const JsonNode &volumeNode); std::map soundChunks; @@ -137,6 +141,9 @@ private: // Because we use the SDL music callback, our music variables must // be protected boost::mutex musicMutex; + //update volume on configuration change + SettingsListener listener; + void onVolumeChange(const JsonNode &volumeNode); std::auto_ptr current; std::auto_ptr next; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 654231afb..0db47d696 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -25,6 +25,7 @@ #include "../lib/CSpellHandler.h" #include "../lib/CTownHandler.h" #include "../lib/BattleState.h" +#include "../lib/JsonNode.h" #include "CMusicHandler.h" #include "../lib/CondSh.h" #include "../lib/NetPacks.h" @@ -96,7 +97,6 @@ CPlayerInterface::CPlayerInterface(int Player) //pim = new boost::recursive_mutex; makingTurn = false; showingDialog = new CondSh(false); - sysOpts = GDefaultOptions; cingconsole = new CInGameConsole; terminate_cond.set(false); firstCall = 1; //if loading will be overwritten in serialize @@ -285,8 +285,9 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details) //first initializing done GH.mainFPSmng->framerateDelay(); // after first move + ui32 speed = settings["adventure"]["heroSpeed"].Float(); //main moving - for(int i=1; i<32; i+=2*sysOpts.heroMoveSpeed) + for(int i=1; i<32; i+=2*speed) { movementPxStep(details, i, hp, ho); adventureInt->updateScreen = true; @@ -1082,7 +1083,6 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus template void CPlayerInterface::serializeTempl( Handler &h, const int version ) { h & playerID; - h & sysOpts; h & spellbookSettings; //sleeping heroes @@ -1099,7 +1099,7 @@ template void CPlayerInterface::serializeTempl( Handler &h, c if (!h.saving) { const CGHeroInstance *hero = cb->getHero(hid); - sleepingHeroes += hero; + sleepingHeroes += hero; } } @@ -1119,7 +1119,7 @@ template void CPlayerInterface::serializeTempl( Handler &h, c if (!h.saving) { const CGHeroInstance *hero = cb->getHero(hid); - wanderingHeroes += hero; + wanderingHeroes += hero; } } } @@ -1132,7 +1132,6 @@ void CPlayerInterface::serialize( COSer &h, const int version ) void CPlayerInterface::serialize( CISer &h, const int version ) { serializeTempl(h,version); - sysOpts.apply(); firstCall = -1; } @@ -1493,7 +1492,7 @@ void CPlayerInterface::update() else GH.simpleRedraw(); - if (conf.cc.showFPS) + if (settings["general"]["showfps"].Bool()) GH.drawFPSCounter(); // draw the mouse cursor and update the screen @@ -2023,74 +2022,6 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI } } -void SystemOptions::setMusicVolume( int newVolume ) -{ - musicVolume = newVolume; - CCS->musich->setVolume(newVolume); - settingsChanged(); -} - -void SystemOptions::setSoundVolume( int newVolume ) -{ - soundVolume = newVolume; - CCS->soundh->setVolume(newVolume); - settingsChanged(); -} - -void SystemOptions::setHeroMoveSpeed( int newSpeed ) -{ - heroMoveSpeed = newSpeed; - settingsChanged(); -} - -void SystemOptions::setMapScrollingSpeed( int newSpeed ) -{ - mapScrollingSpeed = newSpeed; - settingsChanged(); -} - -void SystemOptions::settingsChanged() -{ - CSaveFile settings(GVCMIDirs.UserPath + "/config/sysopts.bin"); - - if(settings.sfile) - settings << *this; - else - tlog1 << "Cannot save settings to config/sysopts.bin!\n"; -} - -void SystemOptions::apply() -{ - if(CCS->musich->getVolume() != musicVolume) - CCS->musich->setVolume(musicVolume); - if(CCS->soundh->getVolume() != soundVolume) - CCS->soundh->setVolume(soundVolume); - - settingsChanged(); -} - -SystemOptions::SystemOptions() -{ - heroMoveSpeed = 2; - mapScrollingSpeed = 2; - musicVolume = 88; - soundVolume = 88; - - printCellBorders = true; - printStackRange = true; - animSpeed = 2; - printMouseShadow = true; - showQueue = true; - - playerName = "Player"; -} - -void SystemOptions::setPlayerName(const std::string &newPlayerName) -{ - playerName = newPlayerName; - settingsChanged(); -} - void CPlayerInterface::eraseCurrentPathOf( const CGHeroInstance * ho, bool checkForExistanceOfPath /*= true */ ) { if(checkForExistanceOfPath) @@ -2140,7 +2071,7 @@ CGPath * CPlayerInterface::getAndVerifyPath(const CGHeroInstance * h) void CPlayerInterface::acceptTurn() { - if(conf.cc.autoSkip) + if(settings["session"]["autoSkip"].Bool()) { while(CInfoWindow *iw = dynamic_cast(GH.topInt())) iw->close(); @@ -2177,7 +2108,7 @@ void CPlayerInterface::acceptTurn() adventureInt->showAll(screen); - if(conf.cc.autoSkip && !LOCPLINT->shiftPressed()) + if(settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed()) { if(CInfoWindow *iw = dynamic_cast(GH.topInt())) iw->close(); diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index eea570d21..93ca45ce9 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -71,42 +71,6 @@ namespace boost class recursive_mutex; }; -/// Stores information about system options like hero move speed, map scrolling speed, creature animation speed,... -struct SystemOptions -{ - std::string playerName; - - ui8 heroMoveSpeed;/*, enemyMoveSpeed*/ //speed of player's hero movement - ui8 mapScrollingSpeed; //map scrolling speed - ui8 musicVolume, soundVolume; - //TODO: rest of system options - - //battle settings - ui8 printCellBorders; //if true, cell borders will be printed - ui8 printStackRange; //if true,range of active stack will be printed - ui8 animSpeed; //speed of animation; 1 - slowest, 2 - medium, 4 - fastest - ui8 printMouseShadow; //if true, hex under mouse will be shaded - ui8 showQueue; - - SystemOptions(); - void setHeroMoveSpeed(int newSpeed); //set for the member above - void setMapScrollingSpeed(int newSpeed); //set the member above - void setMusicVolume(int newVolume); - void setSoundVolume(int newVolume); - void setPlayerName(const std::string &newPlayerName); - void settingsChanged(); //updates file with "default" settings for next running of application - void apply(); - - template void serialize(Handler &h, const int version) - { - h & playerName; - h & heroMoveSpeed & mapScrollingSpeed & musicVolume & soundVolume; - h & printCellBorders & printStackRange & animSpeed & printMouseShadow & showQueue; - } -}; - -extern SystemOptions GDefaultOptions; //defined and inited in CMT.cpp, stores default settings loaded with application - /// Central class for managing user interface logic class CPlayerInterface : public CGameInterface, public IUpdateable { @@ -123,8 +87,6 @@ public: static const int SAVES_COUNT = 5; static int howManyPeople; - SystemOptions sysOpts; - CCastleInterface * castleInt; //NULL if castle window isn't opened static CBattleInterface * battleInt; //NULL if no battle CInGameConsole * cingconsole; diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index d74bbca5c..9de37cf47 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -60,7 +60,6 @@ using boost::ref; #endif void startGame(StartInfo * options, CConnection *serv = NULL); -extern SystemOptions GDefaultOptions; CGPreGame * CGP; ISelectionScreenInfo *SEL; @@ -454,7 +453,7 @@ void CGPreGame::update() GH.topInt()->show(screen); - if (conf.cc.showFPS) + if (settings["general"]["showfps"].Bool()) GH.drawFPSCounter(); // draw the mouse cursor and update the screen @@ -2618,7 +2617,7 @@ CMultiMode::CMultiMode() bar = new CGStatusBar(new CPicture(Rect(7, 465, 440, 18), 0));//226, 472 txt = new CTextInput(Rect(19, 436, 334, 16), *bg); - txt->setText(GDefaultOptions.playerName); //Player + txt->setText(settings["general"]["playerName"].String()); //Player btns[0] = new CAdventureMapButton(CGI->generaltexth->zelp[266], bind(&CMultiMode::openHotseat, this), 373, 78, "MUBHOT.DEF"); btns[1] = new CAdventureMapButton("Host TCP/IP game", "", bind(&CMultiMode::hostTCP, this), 373, 78 + 57*1, "MUBHOST.DEF"); @@ -2633,14 +2632,16 @@ void CMultiMode::openHotseat() void CMultiMode::hostTCP() { - GDefaultOptions.setPlayerName(txt->text); + Settings name = settings.write["general"]["playerName"]; + name->String() = txt->text; GH.popIntTotally(this); GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_HOST)); } void CMultiMode::joinTCP() { - GDefaultOptions.setPlayerName(txt->text); + Settings name = settings.write["general"]["playerName"]; + name->String() = txt->text; GH.popIntTotally(this); GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_GUEST)); } @@ -2688,7 +2689,8 @@ void CHotSeatPlayers::enterSelectionScreen() if(txt[i]->text.length()) names[j++] = txt[i]->text; - GDefaultOptions.setPlayerName(names.begin()->second); //remember selected name + Settings name = settings.write["general"]["playerName"]; + name->String() = names.begin()->second; GH.popInts(2); //pop MP mode window and this GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_HOT_SEAT, &names)); @@ -2866,7 +2868,7 @@ void CBonusSelection::selectMap( int whichOne ) ourHeader->initFromMemory((const unsigned char*)ourCampaign->camp->mapPieces.find(whichOne)->second.c_str(), i); std::map names; - names[1] = GDefaultOptions.playerName; + names[1] = settings["general"]["playerName"].String(); updateStartInfo(ourCampaign->camp->header.filename, sInfo, ourHeader, names); sInfo.turnTime = 0; sInfo.whichMapInCampaign = whichOne; @@ -3283,7 +3285,7 @@ ISelectionScreenInfo::ISelectionScreenInfo(const std::map *Na if(Names && Names->size()) //if have custom set of player names - use it playerNames = *Names; else - playerNames[1] = GDefaultOptions.playerName; //by default we have only one player and his name is "Player" (or whatever the last used name was) + playerNames[1] = settings["general"]["playerName"].String(); //by default we have only one player and his name is "Player" (or whatever the last used name was) } ISelectionScreenInfo::~ISelectionScreenInfo() diff --git a/client/CVideoHandler.cpp b/client/CVideoHandler.cpp index a9757ee38..60731b404 100644 --- a/client/CVideoHandler.cpp +++ b/client/CVideoHandler.cpp @@ -7,7 +7,8 @@ #include "UIFramework/SDL_Extensions.h" #include "CPlayerInterface.h" -extern SystemOptions GDefaultOptions; +extern CGuiHandler GH; //global gui handler + //reads events and returns true on key down static bool keyDown() { diff --git a/client/Client.cpp b/client/Client.cpp index 303ba1bc1..c04c131fd 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -348,7 +348,7 @@ void CClient::newGame( CConnection *con, StartInfo *si ) } int humanPlayers = 0; - int sensibleAILimit = conf.cc.oneGoodAI ? 1 : GameConstants::PLAYER_LIMIT; + int sensibleAILimit = settings["session"]["oneGoodAI"].Bool() ? 1 : GameConstants::PLAYER_LIMIT; for(std::map::iterator it = gs->scenarioOps->playerInfos.begin(); it != gs->scenarioOps->playerInfos.end(); ++it)//initializing interfaces for players { @@ -362,7 +362,7 @@ void CClient::newGame( CConnection *con, StartInfo *si ) CCallback *cb = new CCallback(gs,color,this); if(!it->second.human) { - std::string AItoGive = conf.cc.defaultPlayerAI; + std::string AItoGive = settings["server"]["playerAI"].String(); if(!sensibleAILimit) AItoGive = "GeniusAI"; else @@ -560,7 +560,9 @@ void CClient::battleStarted(const BattleInfo * info) def = NULL; if(att || def || gs->scenarioOps->mode == StartInfo::DUEL) - new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], Rect((conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2, 800, 600), att, def); + new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], + Rect((settings["video"]["gameRes"]["width"].Float() - 800)/2, + (settings["video"]["gameRes"]["height"].Float() - 600)/2, 800, 600), att, def); if(vstd::contains(battleints,info->sides[0])) battleints[info->sides[0]]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 0); @@ -577,7 +579,7 @@ void CClient::battleStarted(const BattleInfo * info) void CClient::loadNeutralBattleAI() { - battleints[255] = CDynLibHandler::getNewBattleAI(conf.cc.defaultBattleAI); + battleints[255] = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String()); battleints[255]->init(new CBattleCallback(gs, 255, this)); } @@ -656,7 +658,7 @@ CConnection * CServerHandler::connectToServer() waitForServer(); th.update(); - CConnection *ret = justConnectToServer(conf.cc.server, port); + CConnection *ret = justConnectToServer(settings["server"]["server"].String(), port); if(verbose) tlog0<<"\tConnecting to the server: "<(conf.cc.port); + port = boost::lexical_cast(settings["server"]["port"].Float()); verbose = false; boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it @@ -701,8 +703,8 @@ CConnection * CServerHandler::justConnectToServer(const std::string &host, const try { tlog0 << "Establishing connection...\n"; - ret = new CConnection( host.size() ? host : conf.cc.server, - port.size() ? port : boost::lexical_cast(conf.cc.port), + ret = new CConnection( host.size() ? host : settings["server"]["server"].String(), + port.size() ? port : boost::lexical_cast(settings["server"]["port"].Float()), NAME); } catch(...) diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 1b3f6a6b5..b0a08c2ed 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -121,7 +121,7 @@ void CGarrisonSlot::hover (bool on) { if(owner->highlighted) { - const CArmedInstance *highl = owner->highlighted->getObj(); + const CArmedInstance *highl = owner->highlighted->getObj(); if( highl->needsLastStack() //we are moving stack from hero's && highl->stacksCount() == 1 //it's only stack && owner->highlighted->upg != upg //we're moving it to the other garrison @@ -195,7 +195,7 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState) CIntObject *creWindow = createCreWindow(myStack, 3, upgr, dism, &pom); GH.pushInt(creWindow); } - else + else { // Only allow certain moves if troops aren't removable or not ours. if ( ( owner->highlighted->our()//our creature is selected @@ -214,7 +214,7 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState) owner->splitting = false; int totalAmount = owner->highlighted->count; - if(creature) + if(creature) totalAmount += count; int last = -1; @@ -254,7 +254,7 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState) } } else // Highlight - { + { if(creature) owner->highlighted = this; redraw(); @@ -360,7 +360,7 @@ void CGarrisonInt::addSplitBtn(CAdventureMapButton * button) void CGarrisonInt::createSet(std::vector &ret, const CCreatureSet * set, int posX, int posY, int distance, int Upg ) { ret.resize(7); - + for(TSlots::const_iterator i=set->Slots().begin(); i!=set->Slots().end(); i++) { ret[i->first] = new CGarrisonSlot(this, posX + (i->first*distance), posY, i->first, Upg, i->second); @@ -395,7 +395,7 @@ void CGarrisonInt::deleteSlots() { for (int i=0; icb->splitStack(armedObjs[highlighted->upg], armedObjs[pb], highlighted->ID, p2, am2); } -CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset, - SDL_Surface *pomsur, const Point& SurOffset, - const CArmedInstance *s1, const CArmedInstance *s2, +CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset, + SDL_Surface *pomsur, const Point& SurOffset, + const CArmedInstance *s1, const CArmedInstance *s2, bool _removableUnits, bool smallImgs, bool _twoRows ) : interx(inx), garOffset(garsOffset), highlighted(NULL), splitting(false), smallIcons(smallImgs), removableUnits (_removableUnits), twoRows(_twoRows) @@ -506,7 +506,7 @@ CInfoWindow::CInfoWindow(std::string Text, int player, const TCompsInfo &comps, CMessage::drawIWindow(this,Text,player); } -CInfoWindow::CInfoWindow() +CInfoWindow::CInfoWindow() { ID = -1; setDelComps(false); @@ -644,8 +644,8 @@ void CInfoPopup::init(int x, int y) // Put the window back on screen if necessary vstd::amax(pos.x, 0); vstd::amax(pos.y, 0); - vstd::amin(pos.x, conf.cc.resx - bitmap->w); - vstd::amin(pos.y, conf.cc.resy - bitmap->h); + vstd::amin(pos.x, screen->w - bitmap->w); + vstd::amin(pos.y, screen->h - bitmap->h); } void CComponent::init(Etype Type, int Subtype, int Val) @@ -768,7 +768,7 @@ SDL_Surface * CComponent::setSurface(std:: string defname, int imagepos) if (img) tlog1<<"CComponent::setSurface: Warning - surface is already set!\n"; CDefEssential * def = CDefHandler::giveDefEss(defname); - + free = true; img = def->ourImages[imagepos].bitmap; img->refcount++;//to preserve surface whed def is deleted @@ -886,7 +886,7 @@ void CSelectableComponent::show(SDL_Surface * to) { CSDL_Ext::drawBorder(to, Rect::around(Rect(pos.x, pos.y, getImg()->w, getImg()->h)), int3(239,215,123)); } - + printAtMiddleWB(subtitle,pos.x+pos.w/2,pos.y+pos.h+25,FONT_SMALL,12,Colors::Cornsilk,to); } @@ -1373,7 +1373,7 @@ void CTownList::clickLeft(tribool down, bool previousState) if (ny>=SIZE || ny<0) return; if(GH.topInt() == adventureInt - && (ny+from)==selected + && (ny+from)==selected && adventureInt->selection->ID == GameConstants::TOWNI_TYPE ) LOCPLINT->openTownWindow(LOCPLINT->towns[selected]);//print town screen @@ -1501,7 +1501,7 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool An OBJ_CONSTRUCTION_CAPTURING_ALL; pos.x+=x; pos.y+=y; - + if(Big) bg = new CPicture(graphics->backgrounds[cre->faction],0,0,false); else @@ -1514,7 +1514,7 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool An CCreaturePic::~CCreaturePic() { - + } void CRecruitmentWindow::close() @@ -1607,7 +1607,7 @@ void CRecruitmentWindow::clickRight(tribool down, bool previousState) void CRecruitmentWindow::showAll(SDL_Surface * to) { CIntObject::showAll(to); - + char pom[15]; SDL_itoa(creatures[which].amount-slider->value,pom,10); //available printAtMiddleLoc(pom,205,253,FONT_SMALL,Colors::Cornsilk,to); @@ -1705,7 +1705,7 @@ void CRecruitmentWindow::initCres() for(int i=0; icreatures.size(); i++) { - if(level >= 0 && i != level) + if(level >= 0 && i != level) continue; for(int j = dwelling->creatures[i].second.size() - 1; j >= 0 ; j--) @@ -1821,13 +1821,13 @@ void CSplitWindow::keyPressed (const SDL_KeyboardEvent & key) { SDLKey k = key.keysym.sym; if (CGuiHandler::isNumKey(k)) //convert numpad number to normal digit - k = CGuiHandler::numToDigit(k); + k = CGuiHandler::numToDigit(k); if(key.state != SDL_PRESSED) return; - int &cur = (which ? a2 : a1), - &sec = (which ? a1 : a2), + int &cur = (which ? a2 : a1), + &sec = (which ? a1 : a2), ncur = cur; if (k == SDLK_BACKSPACE) { @@ -2030,138 +2030,156 @@ CMinorResDataBar::~CMinorResDataBar() SDL_FreeSurface(bg); } -CObjectListWindow::CObjectListWindow(const std::vector &_items, CPicture * titlePic, std::string _title, std::string _descr, - boost::function Callback, int initState) - :title(_title), descr(_descr),items(_items),selected(initState) +CObjectListWindow::CItem::CItem(CObjectListWindow *_parent, size_t _id, std::string _text): + parent(_parent), + index(_id) { - init = false; OBJ_CONSTRUCTION_CAPTURING_ALL; - defActions = ACTIVATE | DEACTIVATE | UPDATE | SHOWALL | DISPOSE | SHARE_POS; - used = LCLICK | KEYBOARD; - - onSelect = Callback; - length = 9; - pos.x = (screen->w-306)/2; - pos.y = (screen->h-468)/2; - - bg = new CPicture("TPGATE.pcx");//x=0, y=0 - bg->colorizeAndConvert(LOCPLINT->playerID); - - slider = new CSlider(277, 120, 256, boost::bind(&CObjectListWindow::moveList,this, _1), length, items.size(), 0, false, 0); - ok = new CAdventureMapButton("","",boost::bind(&CObjectListWindow::elementSelected, this),15,402,"IOKAY.DEF", SDLK_RETURN); - exit = new CAdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally,&GH, this),228,402,"ICANCEL.DEF",SDLK_ESCAPE); - pos.w = bg->pos.w; - pos.h = bg->pos.h; - titleImage = titlePic; - titleImage->pos.x =153+pos.x-titleImage->pos.w/2; - titleImage->pos.y =75 +pos.y-titleImage->pos.h/2; - - for (int i=0; ipos; + used |= LCLICK; + type |= REDRAW_PARENT; + + text = new CLabel(pos.w/2, pos.h/2, FONT_SMALL, CENTER, Colors::Cornsilk, _text); + select(index == parent->selected); } -CObjectListWindow::~CObjectListWindow() +void CObjectListWindow::CItem::select(bool on) { - delete titleImage; + if (on) + border->recActions = 255; + else + border->recActions = ~(UPDATE | SHOWALL); + redraw(); +} + +void CObjectListWindow::CItem::clickLeft(tribool down, bool previousState) +{ + if( previousState && !down) + parent->changeSelection(index); +} + +CObjectListWindow::CObjectListWindow(const std::vector &_items, CPicture * titlePic, std::string _title, std::string _descr, + boost::function Callback): + onSelect(Callback) +{ + items.reserve(_items.size()); + BOOST_FOREACH(int id, _items) + { + items.push_back(std::make_pair(id, CGI->mh->map->objects[id]->hoverName)); + } + + init(titlePic, _title, _descr); +} + +CObjectListWindow::CObjectListWindow(const std::vector &_items, CPicture * titlePic, std::string _title, std::string _descr, + boost::function Callback): + onSelect(Callback) +{ + items.reserve(_items.size()); + + for (size_t i=0; i<_items.size(); i++) + items.push_back(std::make_pair(int(i), _items[i])); + + init(titlePic, _title, _descr); +} + +void CObjectListWindow::init(CPicture * titlePic, std::string _title, std::string _descr) +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + + bg = new CPicture("TPGATE.pcx");//x=0, y=0 + bg->colorizeAndConvert(LOCPLINT->playerID); + pos = bg->center(); + + title = new CLabel(152, 27, FONT_BIG, CENTER, Colors::Jasmine, _title); + descr = new CLabel(145, 133, FONT_SMALL, CENTER, Colors::Cornsilk, _descr); + + ok = new CAdventureMapButton("","",boost::bind(&CObjectListWindow::elementSelected, this),15,402,"IOKAY.DEF", SDLK_RETURN); + ok->block(true); + exit = new CAdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally,&GH, this),228,402,"ICANCEL.DEF",SDLK_ESCAPE); + + if (titlePic) + { + titleImage = titlePic; + addChild(titleImage); + titleImage->recActions = defActions; + titleImage->pos.x =bg->pos.w/2 + pos.x - titleImage->pos.w/2; + titleImage->pos.y =75 + pos.y - titleImage->pos.h/2; + } + list = new CListBox(boost::bind(&CObjectListWindow::genItem, this, _1), CListBox::DestroyFunc(), + Point(15, 152), Point(0, 25), 9, items.size(), 0, 1, Rect(262, -32, 256, 256) ); + list->type |= REDRAW_PARENT; +} + +CIntObject * CObjectListWindow::genItem(size_t index) +{ + if (index < items.size()) + return new CItem(this, index, items[index].second); + return NULL; } void CObjectListWindow::elementSelected() { boost::function toCall = onSelect;//save - int where = items[selected]; //required variables + int where = items[selected].first; //required variables GH.popIntTotally(this);//then destroy window toCall(where);//and send selected object } -void CObjectListWindow::moveList(int which) +void CObjectListWindow::changeSelection(size_t which) { - if (init)//TODO: is there a way to disable running this when CSlider is created? - showAll(screen2); -} + ok->block(false); + if (selected == which) + return; -void CObjectListWindow::clickLeft(tribool down, bool previousState) -{ - if (previousState && (!down)) + std::list< CIntObject * > elements = list->getItems(); + BOOST_FOREACH(CIntObject * element, elements) { - for (int i=0; ivalue+i < items.size() && isItIn(&areas[i],GH.current->motion.x,GH.current->motion.y)) - {//check all areas to find element which was clicked - selected = i+slider->value; - showAll(screen2); - return; - } + CItem *item; + if ( (item = dynamic_cast(element)) ) + if (item->index == selected) + item->select(false); + if (item->index == which) + item->select(true); } + selected = which; } void CObjectListWindow::keyPressed (const SDL_KeyboardEvent & key) { - if(key.state != SDL_PRESSED) return; + if(key.state != SDL_PRESSED) + return; int sel = selected; switch(key.keysym.sym) { - case SDLK_UP: - sel -=1; - break; - case SDLK_DOWN: - sel +=1; - break; - case SDLK_PAGEUP: - sel -=length; - break; - case SDLK_PAGEDOWN: - sel +=length; - break; - case SDLK_HOME: - sel = 0; - break; - case SDLK_END: - sel = slider->amount; - break; - default: - return; - } - if (sel<-1)//nothing was selected & list was moved up - return; - if (sel<0)//start of list reached + break; case SDLK_UP: + sel -=1; + + break; case SDLK_DOWN: + sel +=1; + + break; case SDLK_PAGEUP: + sel -=9; + + break; case SDLK_PAGEDOWN: + sel +=9; + + break; case SDLK_HOME: sel = 0; - if ( sel >= slider->amount )//end of list reached - sel = slider->amount-1; - if ( sel >= items.size() ) - sel = items.size()-1; - if ( sel < slider->value )//need to move list up - slider->moveTo(sel); - else - if ( sel >= slider->value+length )//move to bottom - slider->moveTo(sel-length+1); - selected = sel; - showAll(screen2); -} -void CObjectListWindow::show(SDL_Surface * to) -{ - -} + break; case SDLK_END: + sel = items.size(); -void CObjectListWindow::showAll(SDL_Surface * to) -{ - ok->block((selected<0)?2:0); - CIntObject::showAll(to); - CSDL_Ext::printAtMiddle(title,pos.x+152,pos.y+27,FONT_BIG,Colors::Jasmine,to);//"castle gate" - CSDL_Ext::printAtMiddle(descr,pos.x+145,pos.y+133,FONT_SMALL,Colors::Cornsilk,to);//"select destination" - titleImage->showAll(to); - if ( selected >= slider->value && selected < slider->value+length )//if selected item is visible - { - SDL_Rect a = areas[selected-slider->value]; - CSDL_Ext::drawBorder(to, a.x, a.y, a.w, a.h, int3(255, 231, 148)); - CSDL_Ext::drawBorder(to, a.x-1, a.y-1, a.w+2, a.h+2, int3(255, 231, 148));//border shoul be 2 pixels width + break; default: + return; } - int position = slider->value; - for ( int i = 0; i<9 && imh->map->objects[items[i+position]]->hoverName,pos.x+145,pos.y+163+25*i, - FONT_SMALL, Colors::Cornsilk, to);//print item names in list + + vstd::abetween(sel, 0, items.size()-1); + list->scrollTo(sel); + changeSelection(sel); } CTradeWindow::CTradeableItem::CTradeableItem( EType Type, int ID, bool Left, int Serial) @@ -2254,7 +2272,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState) } else { - if(mw->hRight != this) + if(mw->hRight != this) mw->hRight = this; else return; @@ -2469,7 +2487,7 @@ void CTradeWindow::initItems(bool Left) if(Left || !ids) amount = 7; - else + else amount = ids->size(); if(ids) @@ -2555,7 +2573,7 @@ void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType typ //seven boxes: // X X X // X X X - // X + // X int h, w, x, y, dx, dy; int leftToRightOffset; getBaseForPositions(type, dx, dy, x, y, h, w, !Left, leftToRightOffset); @@ -2665,7 +2683,7 @@ void CTradeWindow::setMode(EMarketMode::EMarketMode Mode) CTradeWindow *nwindow = NULL; GH.popIntTotally(this); - + switch(Mode) { case EMarketMode::CREATURE_EXP: @@ -2748,10 +2766,10 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan } else if(mode == EMarketMode::RESOURCE_ARTIFACT || mode == EMarketMode::ARTIFACT_RESOURCE) { - const std::string &title = market->o->ID == GameConstants::TOWNI_TYPE + const std::string &title = market->o->ID == GameConstants::TOWNI_TYPE ? CGI->buildh->buildings[market->o->subID][17]->Name() : market->o->getHoverText(); - + printAtMiddle(title, 300, 27, FONT_BIG, Colors::Jasmine, *bg); //title } else @@ -2761,7 +2779,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan initItems(false); initItems(true); - + ok = new CAdventureMapButton(CGI->generaltexth->zelp[600],boost::bind(&CGuiHandler::popIntTotally,&GH,this),516,520,"IOK6432.DEF",SDLK_RETURN); ok->assignedKeys.insert(SDLK_ESCAPE); deal = new CAdventureMapButton(CGI->generaltexth->zelp[595],boost::bind(&CMarketplaceWindow::makeDeal,this),307,520,"TPMRKB.DEF"); @@ -2793,10 +2811,10 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan case EMarketMode::RESOURCE_ARTIFACT: printAtMiddle(CGI->generaltexth->allTexts[270],154,148,FONT_SMALL,Colors::Cornsilk,*bg); //kingdom res. break; - case EMarketMode::CREATURE_RESOURCE: + case EMarketMode::CREATURE_RESOURCE: printAtMiddle(boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name), 152, 102, FONT_SMALL, Colors::Cornsilk, *bg); //%s's Creatures break; - case EMarketMode::ARTIFACT_RESOURCE: + case EMarketMode::ARTIFACT_RESOURCE: printAtMiddle(boost::str(boost::format(CGI->generaltexth->allTexts[271]) % hero->name), 152, 57, FONT_SMALL, Colors::Cornsilk, *bg); //%s's Artifacts break; } @@ -2828,7 +2846,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan new CAdventureMapButton(CGI->generaltexth->zelp[599],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::CREATURE_RESOURCE), 516, 485,"TPMRKBU4.DEF"); //was y=450, changed to not overlap res-res in some conditions if(printButtonFor(EMarketMode::RESOURCE_ARTIFACT)) new CAdventureMapButton(CGI->generaltexth->zelp[598],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::RESOURCE_ARTIFACT), 18, 450 + specialOffset,"TPMRKBU2.DEF"); - if(printButtonFor(EMarketMode::ARTIFACT_RESOURCE)) + if(printButtonFor(EMarketMode::ARTIFACT_RESOURCE)) new CAdventureMapButton(CGI->generaltexth->zelp[613],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::ARTIFACT_RESOURCE), 18, 485,"TPMRKBU3.DEF"); //was y=450, changed to not overlap res-art in some conditions updateTraderText(); @@ -2860,7 +2878,7 @@ void CMarketplaceWindow::makeDeal() int sliderValue = 0; if(slider) sliderValue = slider->value; - else + else sliderValue = !deal->isBlocked(); //should always be 1 if(!sliderValue) @@ -2899,11 +2917,11 @@ void CMarketplaceWindow::selectionChanged(bool side) { readyToTrade = hLeft && hRight; if(mode == EMarketMode::RESOURCE_RESOURCE) - readyToTrade = readyToTrade && (hLeft->id != hRight->id); //for resource trade, two DIFFERENT resources must be selected + readyToTrade = readyToTrade && (hLeft->id != hRight->id); //for resource trade, two DIFFERENT resources must be selected - if(mode == EMarketMode::ARTIFACT_RESOURCE && !hLeft) + if(mode == EMarketMode::ARTIFACT_RESOURCE && !hLeft) arts->unmarkSlots(false); - + if(readyToTrade) { int soldItemId = hLeft->id; @@ -2992,8 +3010,8 @@ std::string CMarketplaceWindow::selectionSubtitle(bool Left) const case RESOURCE: case CREATURE: { - int val = slider - ? slider->value * r1 + int val = slider + ? slider->value * r1 : (((deal->isBlocked())) ? 0 : r1); return boost::lexical_cast(val); @@ -3193,7 +3211,7 @@ CAltarWindow::CAltarWindow(const IMarket *Market, const CGHeroInstance *Hero /*= slider = NULL; max = NULL; - + initItems(true); initItems(false); } @@ -3309,7 +3327,7 @@ void CAltarWindow::SacrificeAll() if(t->type == CREATURE) movedAnything = true; } - + deal->block(!movedAnything); calcTotalExp(); } @@ -3557,51 +3575,86 @@ void CAltarWindow::moveFromSlotToAltar(int slotID, CTradeableItem* altarSlot, co } } -CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface * owner) +void CSystemOptionsWindow::setMusicVolume( int newVolume ) { + Settings volume = settings.write["general"]["music"]; + volume->Float() = newVolume; +} + +void CSystemOptionsWindow::setSoundVolume( int newVolume ) +{ + Settings volume = settings.write["general"]["sound"]; + volume->Float() = newVolume; +} + +void CSystemOptionsWindow::setHeroMoveSpeed( int newSpeed ) +{ + Settings speed = settings.write["adventure"]["heroSpeed"]; + speed->Float() = newSpeed; +} + +void CSystemOptionsWindow::setMapScrollingSpeed( int newSpeed ) +{ + Settings speed = settings.write["adventure"]["mapScrollingSpeed"]; + speed->Float() = newSpeed; +} + +CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &Pos, CPlayerInterface * owner) +{ + //TODO: translation and\or config file + static const std::string fsLabel = "Fullscreen"; + static const std::string fsHelp = "{Fullscreen}\n\n If selected, VCMI will run in fullscreen mode, othervice VCMI will run in window"; + static const std::string cwLabel = "Classic creature window"; + static const std::string cwHelp = "{Classic creature window}\n\n Enable original Heroes 3 creature window instead of new window from VCMI"; + static const std::string rsLabel = "Select resolution"; + static const std::string rsHelp = "{Select resolution}\n\n Change in-game screen resolution. Will only affect adventure map. Game restart required to apply new resolution."; + OBJ_CONSTRUCTION_CAPTURING_ALL; - this->pos = pos; - SDL_Surface *hhlp = BitmapHandler::loadBitmap("SysOpbck.bmp", true); - graphics->blueToPlayersAdv(hhlp,LOCPLINT->playerID); - background = SDL_ConvertSurface(hhlp,screen->format,0); - SDL_SetColorKey(background,SDL_SRCCOLORKEY,SDL_MapRGB(background->format,0,255,255)); - SDL_FreeSurface(hhlp); + pos = Pos; + bg = new CPicture("SysOpBck"); + bg->colorize(LOCPLINT->playerID); + //window title + title = new CLabel(242, 32, FONT_BIG, CENTER, Colors::Jasmine, CGI->generaltexth->allTexts[568]); - //printing texts - CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[568], 242, 32, FONT_BIG, Colors::Jasmine, background); //window title - CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[569], 122, 64, FONT_MEDIUM, Colors::Jasmine, background); //hero speed - CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[570], 122, 130, FONT_MEDIUM, Colors::Jasmine, background); //enemy speed - CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[571], 122, 196, FONT_MEDIUM, Colors::Jasmine, background); //map scroll speed - CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[20], 122, 262, FONT_MEDIUM, Colors::Jasmine, background); //video quality - CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[394], 122, 347, FONT_MEDIUM, Colors::Jasmine, background); //music volume - CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[395], 122, 412, FONT_MEDIUM, Colors::Jasmine, background); //effects volume + //left window section + leftGroup = new CLabelGroup(FONT_MEDIUM, CENTER, Colors::Jasmine); + leftGroup->add(122, 64, CGI->generaltexth->allTexts[569]); + leftGroup->add(122, 130, CGI->generaltexth->allTexts[570]); + leftGroup->add(122, 196, CGI->generaltexth->allTexts[571]); + leftGroup->add(122, 262, rsLabel); //CGI->generaltexth->allTexts[20] + leftGroup->add(122, 347, CGI->generaltexth->allTexts[394]); + leftGroup->add(122, 412, CGI->generaltexth->allTexts[395]); - CSDL_Ext::printAt(CGI->generaltexth->allTexts[572], 282, 57, FONT_MEDIUM, Colors::Cornsilk, background); //show move path - CSDL_Ext::printAt(CGI->generaltexth->allTexts[573], 282, 89, FONT_MEDIUM, Colors::Cornsilk, background); //show hero reminder - CSDL_Ext::printAt(CGI->generaltexth->allTexts[574], 282, 121, FONT_MEDIUM, Colors::Cornsilk, background); //quick combat - CSDL_Ext::printAt(CGI->generaltexth->allTexts[575], 282, 153, FONT_MEDIUM, Colors::Cornsilk, background); //video subtitles - CSDL_Ext::printAt(CGI->generaltexth->allTexts[576], 282, 185, FONT_MEDIUM, Colors::Cornsilk, background); //town building outlines - CSDL_Ext::printAt(CGI->generaltexth->allTexts[577], 282, 217, FONT_MEDIUM, Colors::Cornsilk, background); //spell book animation + //right section + rightGroup = new CLabelGroup(FONT_MEDIUM, TOPLEFT, Colors::Cornsilk); + rightGroup->add(282, 57, CGI->generaltexth->allTexts[572]); + rightGroup->add(282, 89, CGI->generaltexth->allTexts[573]); + rightGroup->add(282, 121, CGI->generaltexth->allTexts[574]); + rightGroup->add(282, 153, CGI->generaltexth->allTexts[575]); + rightGroup->add(282, 185, cwLabel); //CGI->generaltexth->allTexts[576] + rightGroup->add(282, 217, fsLabel); //CGI->generaltexth->allTexts[577] //setting up buttons // load = new CAdventureMapButton (CGI->generaltexth->zelp[321].first, CGI->generaltexth->zelp[321].second, boost::bind(&CSystemOptionsWindow::loadf, this), pos.x+246, pos.y+298, "SOLOAD.DEF", SDLK_l); - // std::swap(save->imgs[0][0], load->imgs[0][1]); - save = new CAdventureMapButton (CGI->generaltexth->zelp[322].first, CGI->generaltexth->zelp[322].second, boost::bind(&CSystemOptionsWindow::bsavef, this), 357, 298, "SOSAVE.DEF", SDLK_s); + save = new CAdventureMapButton (CGI->generaltexth->zelp[322].first, CGI->generaltexth->zelp[322].second, + boost::bind(&CSystemOptionsWindow::bsavef, this), 357, 298, "SOSAVE.DEF", SDLK_s); save->swappedImages = true; save->update(); // restart = new CAdventureMapButton (CGI->generaltexth->zelp[323].first, CGI->generaltexth->zelp[323].second, boost::bind(&CSystemOptionsWindow::bmainmenuf, this), pos.x+346, pos.y+357, "SORSTRT", SDLK_r); - // std::swap(save->imgs[0][0], restart->imgs[0][1]); - mainMenu = new CAdventureMapButton (CGI->generaltexth->zelp[320].first, CGI->generaltexth->zelp[320].second, boost::bind(&CSystemOptionsWindow::bmainmenuf, this), 357, 357, "SOMAIN.DEF", SDLK_m); + mainMenu = new CAdventureMapButton (CGI->generaltexth->zelp[320].first, CGI->generaltexth->zelp[320].second, + boost::bind(&CSystemOptionsWindow::bmainmenuf, this), 357, 357, "SOMAIN.DEF", SDLK_m); mainMenu->swappedImages = true; mainMenu->update(); - quitGame = new CAdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second, boost::bind(&CSystemOptionsWindow::bquitf, this), 246, 415, "soquit.def", SDLK_q); + quitGame = new CAdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second, + boost::bind(&CSystemOptionsWindow::bquitf, this), 246, 415, "soquit.def", SDLK_q); quitGame->swappedImages = true; quitGame->update(); - backToMap = new CAdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second, boost::bind(&CSystemOptionsWindow::breturnf, this), 357, 415, "soretrn.def", SDLK_RETURN); + backToMap = new CAdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second, + boost::bind(&CSystemOptionsWindow::breturnf, this), 357, 415, "soretrn.def", SDLK_RETURN); backToMap->swappedImages = true; backToMap->update(); backToMap->assignedKeys.insert(SDLK_ESCAPE); @@ -3611,36 +3664,79 @@ CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface heroMoveSpeed->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[350].second),CGI->generaltexth->zelp[350].second, "sysopb2.def", 76, 77, 2); heroMoveSpeed->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[351].second),CGI->generaltexth->zelp[351].second, "sysopb3.def", 124, 77, 4); heroMoveSpeed->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[352].second),CGI->generaltexth->zelp[352].second, "sysopb4.def", 172, 77, 8); - heroMoveSpeed->select(owner->sysOpts.heroMoveSpeed, 1); - heroMoveSpeed->onChange = boost::bind(&SystemOptions::setHeroMoveSpeed, &owner->sysOpts, _1); + heroMoveSpeed->select(settings["adventure"]["heroSpeed"].Float(), 1); + heroMoveSpeed->onChange = boost::bind(&CSystemOptionsWindow::setHeroMoveSpeed, this, _1); mapScrollSpeed = new CHighlightableButtonsGroup(0); mapScrollSpeed->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[357].second),CGI->generaltexth->zelp[357].second, "sysopb9.def", 28, 210, 1); mapScrollSpeed->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[358].second),CGI->generaltexth->zelp[358].second, "sysob10.def", 92, 210, 2); mapScrollSpeed->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[359].second),CGI->generaltexth->zelp[359].second, "sysob11.def", 156, 210, 4); - mapScrollSpeed->select(owner->sysOpts.mapScrollingSpeed, 1); - mapScrollSpeed->onChange = boost::bind(&SystemOptions::setMapScrollingSpeed, &owner->sysOpts, _1); + mapScrollSpeed->select(settings["adventure"]["scrollSpeed"].Float(), 1); + mapScrollSpeed->onChange = boost::bind(&CSystemOptionsWindow::setMapScrollingSpeed, this, _1); musicVolume = new CHighlightableButtonsGroup(0, true); for(int i=0; i<10; ++i) - { musicVolume->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[326+i].second),CGI->generaltexth->zelp[326+i].second, "syslb.def", 29 + 19*i, 359, i*11); - } + musicVolume->select(CCS->musich->getVolume(), 1); - musicVolume->onChange = boost::bind(&SystemOptions::setMusicVolume, &owner->sysOpts, _1); + musicVolume->onChange = boost::bind(&CSystemOptionsWindow::setMusicVolume, this, _1); effectsVolume = new CHighlightableButtonsGroup(0, true); for(int i=0; i<10; ++i) - { effectsVolume->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[336+i].second),CGI->generaltexth->zelp[336+i].second, "syslb.def", 29 + 19*i, 425, i*11); - } + effectsVolume->select(CCS->soundh->getVolume(), 1); - effectsVolume->onChange = boost::bind(&SystemOptions::setSoundVolume, &owner->sysOpts, _1); + effectsVolume->onChange = boost::bind(&CSystemOptionsWindow::setSoundVolume, this, _1); + + showReminder = new CHighlightableButton( + boost::bind(&CSystemOptionsWindow::toggleReminder, this, true), boost::bind(&CSystemOptionsWindow::toggleReminder, this, false), + std::map(), CGI->generaltexth->zelp[361].second, false, "sysopchk.def", NULL, 246, 87, false); + + newCreatureWin = new CHighlightableButton( + boost::bind(&CSystemOptionsWindow::toggleCreatureWin, this, true), boost::bind(&CSystemOptionsWindow::toggleCreatureWin, this, false), + std::map(), cwHelp, false, "sysopchk.def", NULL, 246, 183, false); + + fullscreen = new CHighlightableButton( + boost::bind(&CSystemOptionsWindow::toggleFullscreen, this, true), boost::bind(&CSystemOptionsWindow::toggleFullscreen, this, false), + std::map(), fsHelp, false, "sysopchk.def", NULL, 246, 215, false); + + showReminder->select(settings["adventure"]["heroReminder"].Bool()); + newCreatureWin->select(settings["general"]["classicCreatureWindow"].Bool()); + fullscreen->select(settings["video"]["fullscreen"].Bool()); + + gameResButton = new CAdventureMapButton("", rsHelp, boost::bind(&CSystemOptionsWindow::selectGameRes, this, false), 28, 275,"SYSOB12", SDLK_g); } -CSystemOptionsWindow::~CSystemOptionsWindow() +void CSystemOptionsWindow::selectGameRes(bool pregame) { - SDL_FreeSurface(background); + assert(pregame == false);//TODO + + //TODO: translation and\or config file + static const std::string rsLabel = "Select resolution"; + static const std::string rsHelp = "Change in-game screen resolution."; + + std::vector items; + + BOOST_FOREACH( config::CConfigHandler::GuiOptionsMap::value_type& value, conf.guiOptions) + { + std::string resX = boost::lexical_cast(value.first.first); + std::string resY = boost::lexical_cast(value.first.second); + items.push_back(resX + 'x' + resY); + } + + GH.pushInt(new CObjectListWindow(items, NULL, rsLabel, rsHelp, + boost::bind(&CSystemOptionsWindow::setGameRes, this, pregame, _1))); +} + +void CSystemOptionsWindow::setGameRes(bool pregame, int index) +{ + config::CConfigHandler::GuiOptionsMap::const_iterator iter = conf.guiOptions.begin(); + while (index--) + iter++; + + Settings gameRes = settings.write["video"]["gameRes"]; + gameRes["width"].Float() = iter->first.first; + gameRes["height"].Float() = iter->first.second; } void CSystemOptionsWindow::pushSDLEvent(int type, int usercode) @@ -3653,6 +3749,24 @@ void CSystemOptionsWindow::pushSDLEvent(int type, int usercode) SDL_PushEvent(&event); } +void CSystemOptionsWindow::toggleReminder(bool on) +{ + Settings heroReminder = settings.write["adventure"]["heroReminder"]; + heroReminder->Bool() = on; +} + +void CSystemOptionsWindow::toggleCreatureWin(bool on) +{ + Settings classicCreatureWindow = settings.write["general"]["classicCreatureWindow"]; + classicCreatureWindow->Bool() = on; +} + +void CSystemOptionsWindow::toggleFullscreen(bool on) +{ + Settings fullscreen = settings.write["video"]["fullscreen"]; + fullscreen->Bool() = on; +} + void CSystemOptionsWindow::bquitf() { LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], std::vector(), boost::bind(&CSystemOptionsWindow::pushSDLEvent, this, SDL_QUIT, 0), 0, false); @@ -3672,20 +3786,6 @@ void CSystemOptionsWindow::bsavef() { GH.popIntTotally(this); GH.pushInt(new CSavingScreen(CPlayerInterface::howManyPeople > 1)); - /*using namespace boost::posix_time; - std::ostringstream fnameStream; - fnameStream << second_clock::local_time(); - std::string fname = fnameStream.str(); - boost::algorithm::replace_all(fname,":",""); - boost::algorithm::replace_all(fname," ","-"); - LOCPLINT->showYesNoDialog("Do you want to save current game as " + fname, std::vector(), boost::bind(&CCallback::save, LOCPLINT->cb, fname), boost::bind(&CSystemOptionsWindow::activate, this), false);*/ -} - -void CSystemOptionsWindow::showAll(SDL_Surface * to) -{ - CSDL_Ext::blitSurface(background, NULL, to, &pos); - - CIntObject::showAll(to); } CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj) @@ -3776,7 +3876,7 @@ void CTavernWindow::show(SDL_Surface * to) { HeroPortrait *sel = selected ? h2 : h1; - if (selected != oldSelected && !recruit->isBlocked()) + if (selected != oldSelected && !recruit->isBlocked()) { // Selected hero just changed. Update RECRUIT button hover text if recruitment is allowed. oldSelected = selected; @@ -3822,7 +3922,7 @@ CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const int artifs = h->artifactsWorn.size() + h->artifactsInBackpack.size(); for(int i=13; i<=17; i++) //war machines and spellbook don't count - if(vstd::contains(h->artifactsWorn,i)) + if(vstd::contains(h->artifactsWorn,i)) artifs--; sprintf_s(descr, sizeof(descr),CGI->generaltexth->allTexts[215].c_str(), h->name.c_str(), h->level, h->type->heroClass->name.c_str(), artifs); @@ -3830,7 +3930,7 @@ CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const } } - + void CTavernWindow::HeroPortrait::show(SDL_Surface * to) { blitAt(graphics->portraitLarge[h->subID],pos,to); @@ -4144,10 +4244,10 @@ void CArtPlace::activate() void CArtPlace::clickLeft(tribool down, bool previousState) { //LRClickableAreaWTextComp::clickLeft(down); - bool inBackpack = slotID >= GameConstants::BACKPACK_START, + bool inBackpack = slotID >= GameConstants::BACKPACK_START, srcInBackpack = ourOwner->commonInfo->src.slotID >= GameConstants::BACKPACK_START, srcInSameHero = ourOwner->commonInfo->src.AOH == ourOwner; - + if(ourOwner->highlightModeCallback && ourArt) { if(down) @@ -4171,7 +4271,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState) { if(ourArt->artType->id == 0) { - CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (conf.cc.resx - 620)/2, (conf.cc.resy - 595)/2), ourOwner->curHero, LOCPLINT, LOCPLINT->battleInt); + CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), ourOwner->curHero, LOCPLINT, LOCPLINT->battleInt); GH.pushInt(spellWindow); } } @@ -4242,12 +4342,12 @@ void CArtPlace::clickLeft(tribool down, bool previousState) (!ourArt || ourOwner->curHero->tempOwner == LOCPLINT->playerID)) { setMeAsDest(); -// +// // // Special case when the dest artifact can't be fit into the src slot. // //CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID); // const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->src.AOH; // ui16 srcSlotID = ourOwner->commonInfo->src.slotID; -// if (ourArt && srcSlotID < 19 && !ourArt->canBePutAt(ArtifactLocation(srcAOH->curHero, srcSlotID))) +// if (ourArt && srcSlotID < 19 && !ourArt->canBePutAt(ArtifactLocation(srcAOH->curHero, srcSlotID))) // { // // Put dest artifact into owner's backpack. // ourOwner->commonInfo->src.AOH = ourOwner; @@ -4264,14 +4364,14 @@ void CArtPlace::clickRight(tribool down, bool previousState) { if(down && ourArt && !locked && text.size() && !picked) //if there is no description or it's a lock, do nothing ;] { - if (slotID < 19) + if (slotID < 19) { if(ourOwner->allowedAssembling) { std::vector assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero); // If the artifact can be assembled, display dialog. - BOOST_FOREACH(const CArtifact *combination, assemblyPossibilities) + BOOST_FOREACH(const CArtifact *combination, assemblyPossibilities) { LOCPLINT->showArtifactAssemblyDialog( ourArt->artType->id, @@ -4380,14 +4480,14 @@ void CArtPlace::showAll(SDL_Surface * to) if(marked && active) { // Draw vertical bars. - for (int i = 0; i < pos.h; ++i) + for (int i = 0; i < pos.h; ++i) { CSDL_Ext::SDL_PutPixelWithoutRefresh(to, pos.x, pos.y + i, 240, 220, 120); CSDL_Ext::SDL_PutPixelWithoutRefresh(to, pos.x + pos.w - 1, pos.y + i, 240, 220, 120); } // Draw horizontal bars. - for (int i = 0; i < pos.w; ++i) + for (int i = 0; i < pos.w; ++i) { CSDL_Ext::SDL_PutPixelWithoutRefresh(to, pos.x + i, pos.y, 240, 220, 120); CSDL_Ext::SDL_PutPixelWithoutRefresh(to, pos.x + i, pos.y + pos.h - 1, 240, 220, 120); @@ -4559,56 +4659,56 @@ void CArtifactsOfHero::SCommonPart::reset() void CArtifactsOfHero::setHero(const CGHeroInstance * hero) { // // An update is made, rather than initialization. -// if (curHero && curHero->id == hero->id) +// if (curHero && curHero->id == hero->id) // { // if(curHero != hero) // { // //delete curHero; // curHero = hero; //was: creating a copy // } -// +// // // Compensate backpack pos if an artifact was insertad before it. // if (commonInfo->dst.slotID >= 19 && commonInfo->destAOH == this // && commonInfo->dst.slotID - 19 < backpackPos) // { // backpackPos++; // } -// -// if (updateState && commonInfo->srcAOH == this) +// +// if (updateState && commonInfo->srcAOH == this) // { // // A swap was made, make the replaced artifact the current selected. -// if (commonInfo->dst.slotID < 19 && commonInfo->destArtifact) +// if (commonInfo->dst.slotID < 19 && commonInfo->destArtifact) // { // // // Temporarily remove artifact from hero. // // if (commonInfo->srcSlotID < 19) // // CGI->arth->unequipArtifact(curHero->artifWorn, commonInfo->srcSlotID); // // else // // curHero->artifacts.erase(curHero->artifacts.begin() + (commonInfo->srcSlotID - 19)); -// +// // updateParentWindow(); //TODO: evil! but does the thing -// +// // // Source <- Dest // commonInfo->srcArtifact = commonInfo->destArtifact; -// +// // // Reset destination parameters. // commonInfo->dst.clear(); -// +// // CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[commonInfo->srcArtifact->id].bitmap); // markPossibleSlots(commonInfo->srcArtifact); -// } -// else if (commonInfo->destAOH != NULL) +// } +// else if (commonInfo->destAOH != NULL) // { // // Reset all parameters. // commonInfo->reset(); // unmarkSlots(); // } // } -// } -// else +// } +// else // { // commonInfo->reset(); // } -// +// // if(hero != curHero) // { // // delete curHero; @@ -4648,12 +4748,12 @@ void CArtifactsOfHero::scrollBackpack(int dir) std::multiset toOmit = artifactsOnAltar; if(commonInfo->src.art) //if we picked an art from backapck, its slot has to be omitted toOmit.insert(commonInfo->src.art); - + int omitedSoFar = 0; //set new data size_t s = 0; - for( ; s < artsInBackpack; ++s) + for( ; s < artsInBackpack; ++s) { if (s < artsInBackpack) @@ -4662,7 +4762,7 @@ void CArtifactsOfHero::scrollBackpack(int dir) const CArtifactInstance *art = curHero->getArt(slotID); assert(art); if(!vstd::contains(toOmit, art)) - { + { if(s - omitedSoFar < backpack.size()) setSlotData(backpack[s-omitedSoFar], slotID); } @@ -4709,7 +4809,7 @@ void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art) BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants) BOOST_FOREACH(CArtPlace *place, aoh->artWorn) place->marked = art->canBePutAt(ArtifactLocation(aoh->curHero, place->slotID), true); - + safeRedraw(); } @@ -4751,7 +4851,7 @@ void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, int slotID) artPlace->picked = false; artPlace->slotID = slotID; - + if(const ArtSlotInfo *asi = curHero->getSlot(slotID)) { artPlace->setArtifact(asi->artifact); @@ -4759,7 +4859,7 @@ void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, int slotID) } else artPlace->setArtifact(NULL); -} +} /** * Makes given artifact slot appear as empty with a certain slot ID. @@ -4785,7 +4885,7 @@ CArtifactsOfHero::CArtifactsOfHero(std::vector ArtWorn, std::vector commonInfo = new CArtifactsOfHero::SCommonPart; commonInfo->participants.insert(this); } - + // Init slots for worn artifacts. for (size_t g = 0; g < artWorn.size() ; g++) { @@ -4816,14 +4916,14 @@ CArtifactsOfHero::CArtifactsOfHero(const Point& position, bool createCommonPart OBJ_CONSTRUCTION_CAPTURING_ALL; pos += position; artWorn.resize(19); - + std::vector slotPos; - slotPos += genRect(44,44,509,30), genRect(44,44,567,240), genRect(44,44,509,80), - genRect(44,44,383,68), genRect(44,44,564,183), genRect(44,44,509,130), - genRect(44,44,431,68), genRect(44,44,610,183), genRect(44,44,515,295), + slotPos += genRect(44,44,509,30), genRect(44,44,567,240), genRect(44,44,509,80), + genRect(44,44,383,68), genRect(44,44,564,183), genRect(44,44,509,130), + genRect(44,44,431,68), genRect(44,44,610,183), genRect(44,44,515,295), genRect(44,44,383,143), genRect(44,44,399,194), genRect(44,44,415,245), - genRect(44,44,431,296), genRect(44,44,564,30), genRect(44,44,610,30), - genRect(44,44,610,76), genRect(44,44,610,122), genRect(44,44,610,310), + genRect(44,44,431,296), genRect(44,44,564,30), genRect(44,44,610,30), + genRect(44,44,610,76), genRect(44,44,610,122), genRect(44,44,610,310), genRect(44,44,381,296); // Create slots for worn artifacts. @@ -4860,13 +4960,13 @@ CArtifactsOfHero::~CArtifactsOfHero() void CArtifactsOfHero::updateParentWindow() { - if (CHeroWindow* chw = dynamic_cast(GH.topInt())) + if (CHeroWindow* chw = dynamic_cast(GH.topInt())) { if(updateState) chw->curHero = curHero; else chw->update(curHero, true); - } + } else if(CExchangeWindow* cew = dynamic_cast(GH.topInt())) { @@ -4901,7 +5001,7 @@ void CArtifactsOfHero::safeRedraw() { if(parent) parent->redraw(); - else + else redraw(); } } @@ -4910,7 +5010,7 @@ void CArtifactsOfHero::realizeCurrentTransaction() { assert(commonInfo->src.AOH); assert(commonInfo->dst.AOH); - LOCPLINT->cb->swapArtifacts(commonInfo->src.AOH->curHero, commonInfo->src.slotID, + LOCPLINT->cb->swapArtifacts(commonInfo->src.AOH->curHero, commonInfo->src.slotID, commonInfo->dst.AOH->curHero, commonInfo->dst.slotID); } @@ -4922,7 +5022,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact updateSlot(dst.slot); if(src.hero == curHero || dst.hero == curHero) //we need to update all slots, artifact might be combined and affect more slots updateWornSlots(false); - + if (src.hero != curHero && dst.hero != curHero) return; @@ -4961,7 +5061,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact markPossibleSlots(dst.getArt()); } } - else if(src.slot >= GameConstants::BACKPACK_START && + else if(src.slot >= GameConstants::BACKPACK_START && src.slot < commonInfo->src.slotID && src.hero == commonInfo->src.AOH->curHero) //artifact taken from before currently picked one { @@ -4981,7 +5081,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact int shift = 0; // if(dst.slot >= Arts::BACKPACK_START && dst.slot - Arts::BACKPACK_START < backpackPos) // shift++; -// +// if(src.slot < GameConstants::BACKPACK_START && dst.slot - GameConstants::BACKPACK_START < backpackPos) shift++; if(dst.slot < GameConstants::BACKPACK_START && src.slot - GameConstants::BACKPACK_START < backpackPos) @@ -5156,7 +5256,7 @@ CExchangeWindow::CExchangeWindow(si32 hero1, si32 hero2) : bg(NULL) pos.w = screen->w; pos.h = screen->h; - + artifs[0] = new CArtifactsOfHero(Point(pos.x + -334, pos.y + 150)); artifs[0]->commonInfo = new CArtifactsOfHero::SCommonPart; artifs[0]->commonInfo->participants.insert(artifs[0]); @@ -5237,7 +5337,7 @@ CExchangeWindow::CExchangeWindow(si32 hero1, si32 hero2) : bg(NULL) questlogButton[0] = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], std::string(), boost::bind(&CExchangeWindow::questlog,this, 0), pos.x+10, pos.y+44, "hsbtns4.def"); questlogButton[1] = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], std::string(), boost::bind(&CExchangeWindow::questlog,this, 1), pos.x+740, pos.y+44, "hsbtns4.def"); - //statusbar + //statusbar //FIXME - this image is a bit bigger than required - part of background should be used instead ourBar = new CGStatusBar(pos.x + 3, pos.y + 577, "KSTATBAR"); @@ -5314,7 +5414,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 &grailPos, double discoveredRatio) //the rest background = SDL_ConvertSurface(back, screen->format, back->flags); SDL_FreeSurface(back); - pos = genRect(background->h, background->w, (conf.cc.resx - background->w) / 2, (conf.cc.resy - background->h) / 2); + pos = genRect(background->h, background->w, (screen->w - background->w) / 2, (screen->h - background->h) / 2); quitb = new CAdventureMapButton(CGI->generaltexth->allTexts[599], "", boost::bind(&CGuiHandler::popIntTotally, &GH, this), pos.x+670, pos.y+538, "IOK6432.DEF", SDLK_RETURN); quitb->assignedKeys.insert(SDLK_ESCAPE); quitb->borderColor = Colors::MetallicGold; @@ -5441,14 +5541,14 @@ CTransformerWindow::CItem::CItem(CTransformerWindow * _parent, int _size, int _i left = true; pos.w = 58; pos.h = 64; - + pos.x += 45 + (id%3)*83 + id/6*83; pos.y += 109 + (id/3)*98; } CTransformerWindow::CItem::~CItem() { - + } void CTransformerWindow::showAll(SDL_Surface * to) @@ -5481,16 +5581,16 @@ CTransformerWindow::CTransformerWindow(const CGHeroInstance * _hero, const CGTow bg = new CPicture ("SKTRNBK.PCX"); bg->colorizeAndConvert(LOCPLINT->playerID); pos = center(bg->pos); - + if (hero) army = hero; else army = town; - + for (int i=0; i<7; i++ ) if ( army->getCreature(i) ) items.push_back(new CItem(this, army->getStackCount(i), i)); - + all = new CAdventureMapButton(CGI->generaltexth->zelp[590],boost::bind(&CTransformerWindow::addAll,this), 146,416,"ALTARMY.DEF",SDLK_a); convert= new CAdventureMapButton(CGI->generaltexth->zelp[591],boost::bind(&CTransformerWindow::makeDeal,this), 269,416,"ALTSACR.DEF",SDLK_RETURN); cancel = new CAdventureMapButton(CGI->generaltexth->zelp[592],boost::bind(&CGuiHandler::popIntTotally,&GH, this),392,416,"ICANCEL.DEF",SDLK_ESCAPE); @@ -5499,7 +5599,7 @@ CTransformerWindow::CTransformerWindow(const CGHeroInstance * _hero, const CGTow CTransformerWindow::~CTransformerWindow() { - + } void CUniversityWindow::CItem::clickLeft(tribool down, bool previousState) @@ -5566,12 +5666,12 @@ void CUniversityWindow::CItem::showAll(SDL_Surface * to) break; } assert(bar); - + blitAtLoc(bar->bg, -28, -22, to); blitAtLoc(bar->bg, -28, 48, to); printAtMiddleLoc (CGI->generaltexth->skillName[ID], 22, -13, FONT_SMALL, Colors::Cornsilk,to);//Name printAtMiddleLoc (CGI->generaltexth->levels[0], 22, 57, FONT_SMALL, Colors::Cornsilk,to);//Level(always basic) - + CPicture::showAll(to); } @@ -5586,7 +5686,7 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket OBJ_CONSTRUCTION_CAPTURING_ALL; bg = new CPicture("UNIVERS1.PCX"); bg->colorizeAndConvert(LOCPLINT->playerID); - + green = new CPicture("UNIVGREN.PCX"); yellow = new CPicture("UNIVGOLD.PCX");//bars red = new CPicture("UNIVRED.PCX"); @@ -5617,17 +5717,17 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket tlog0<<"\t\tIncorrect size of available items vector!\n"; for (int i=0; ipos); cancel = new CAdventureMapButton(CGI->generaltexth->zelp[632], boost::bind(&CGuiHandler::popIntTotally,&GH, this),200,313,"IOKAY.DEF",SDLK_RETURN); - + bar = new CGStatusBar(232, 371); } CUniversityWindow::~CUniversityWindow() { - + } CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * PARENT, int SKILL, bool available ):parent(PARENT) @@ -5652,7 +5752,7 @@ CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * PARENT, int SKILL, bo std::string hoverText = CGI->generaltexth->allTexts[609]; boost::replace_first(hoverText, "%s", CGI->generaltexth->levels[0]+ " " + CGI->generaltexth->skillName[SKILL]); - + text = CGI->generaltexth->zelp[633].second; boost::replace_first(text, "%s", CGI->generaltexth->levels[0]); boost::replace_first(text, "%s", CGI->generaltexth->skillName[SKILL]); @@ -5661,7 +5761,7 @@ CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * PARENT, int SKILL, bo confirm= new CAdventureMapButton(hoverText, text, boost::bind(&CUnivConfirmWindow::makeDeal, this, SKILL), 148,299,"IBY6432.DEF",SDLK_RETURN); confirm->block(!available); - + cancel = new CAdventureMapButton(CGI->generaltexth->zelp[631],boost::bind(&CGuiHandler::popIntTotally, &GH, this), 252,299,"ICANCEL.DEF",SDLK_ESCAPE); bar = new CGStatusBar(232, 371); @@ -5677,17 +5777,17 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance *visitor, const CGObjectIn fort(object),hero(visitor) { OBJ_CONSTRUCTION_CAPTURING_ALL; - + slotsCount=7; resources = CDefHandler::giveDefEss("SMALRES.DEF"); bg = new CPicture("APHLFTBK.PCX"); bg->colorizeAndConvert(LOCPLINT->playerID); - + printAtMiddleLoc (fort->hoverName, 325, 32, FONT_BIG, Colors::Jasmine, bg->bg);//Hill Fort pos = center(bg->pos); heroPic = new CHeroArea(30, 60, hero); - + currState.resize(slotsCount+1); costs.resize(slotsCount); totalSumm.resize(GameConstants::RESOURCE_QUANTITY); @@ -5714,7 +5814,7 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance *visitor, const CGObjectIn CHillFortWindow::~CHillFortWindow() { - + } void CHillFortWindow::activate() @@ -5725,10 +5825,10 @@ void CHillFortWindow::activate() void CHillFortWindow::updateGarrisons() { - + for (int i=0; isetIndex(newState); upgrade[i]->block(currState[i] == -1); upgrade[i]->hoverTexts[0] = getTextForSlot(i); } - + int newState = getState(slotsCount); currState[slotsCount] = newState; upgradeAll->setIndex(newState); @@ -5762,11 +5862,11 @@ void CHillFortWindow::makeDeal(int slot) switch (currState[slot]) { case 0: - LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[314 + offset], + LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[314 + offset], std::vector(), soundBase::sound_todo); break; case 1: - LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[313 + offset], + LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[313 + offset], std::vector(), soundBase::sound_todo); break; case 2: @@ -5778,14 +5878,14 @@ void CHillFortWindow::makeDeal(int slot) LOCPLINT->cb->upgradeCreature(hero, i, info.newID[0]); } break; - + } } void CHillFortWindow::showAll (SDL_Surface *to) { CIntObject::showAll(to); - + for ( int i=0; igetCreature(slot)->nameSing); else boost::algorithm::replace_first(str,"%s",hero->getCreature(slot)->namePl); - + return str; } @@ -5843,7 +5943,7 @@ int CHillFortWindow::getState(int slot) bool allUpgraded = true;//All creatures are upgraded? for (int i=0; islotEmpty(slot))//no creature here return -1; - + UpgradeInfo info; LOCPLINT->cb->getUpgradeInfo(hero, slot, info); if (!info.newID.size())//already upgraded @@ -6062,7 +6162,7 @@ void MoraleLuckBox::set(const IBonusBearer *node) int mrlt = -9; TModDescr mrl; - + if (node) { node->getModifiersWDescr(mrl, bonusType[morale]); @@ -6100,7 +6200,7 @@ void MoraleLuckBox::showAll(SDL_Surface * to) else def = morale ? graphics->morale42 : graphics->luck42; SDL_Surface *img = def->ourImages[bonusValue + 3].bitmap; - + blitAt(img, Rect(img).centerIn(pos), to); //put img in the center of our pos } @@ -6249,7 +6349,7 @@ CRClickPopupInt::CRClickPopupInt( IShowActivatable *our, bool deleteInt ) CRClickPopupInt::~CRClickPopupInt() { - // //workaround for hero window issue - if it's our interface, call dispose to properly reset it's state + // //workaround for hero window issue - if it's our interface, call dispose to properly reset it's state // //TODO? it might be better to rewrite hero window so it will bee newed/deleted on opening / closing (not effort-worthy now, but on some day...?) // if(LOCPLINT && inner == adventureInt->heroWindow) // adventureInt->heroWindow->dispose(); diff --git a/client/GUIClasses.h b/client/GUIClasses.h index df2a651ba..5909de70e 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -74,7 +74,7 @@ class CArtPlace; class CAnimImage; /// text + comp. + ok button -class CInfoWindow : public CSimpleWindow +class CInfoWindow : public CSimpleWindow { //window able to delete its components when closed bool delComps; //whether comps will be deleted @@ -103,7 +103,7 @@ public: }; /// component selection window -class CSelWindow : public CInfoWindow +class CSelWindow : public CInfoWindow { //warning - this window deletes its components by closing! public: void selectionChange(unsigned to); @@ -114,7 +114,7 @@ public: }; /// popup displayed on R-click -class CRClickPopup : public CIntObject +class CRClickPopup : public CIntObject { public: virtual void activate(); @@ -130,7 +130,7 @@ public: }; /// popup displayed on R-click -class CRClickPopupInt : public CRClickPopup +class CRClickPopupInt : public CRClickPopup { public: IShowActivatable *inner; @@ -173,7 +173,7 @@ public: SDL_Surface *img; //our image bool free; //should surface be freed on delete - + SDL_Surface * setSurface(std::string defName, int imgPos); void init(Etype Type, int Subtype, int Val); @@ -246,7 +246,7 @@ public: int p2, //TODO: comment me shiftPos;//1st slot of the second row, set shiftPoint for effect - bool splitting, pb, + bool splitting, pb, smallIcons, //true - 32x32 imgs, false - 58x64 removableUnits,//player can remove units from up twoRows,//slots will be placed in 2 rows @@ -262,7 +262,7 @@ public: void setArmy(const CArmedInstance *army, bool bottomGarrison); void addSplitBtn(CAdventureMapButton * button); void createSet(std::vector &ret, const CCreatureSet * set, int posX, int distance, int posY, int Upg ); - + void activate(); void createSlots(); void deleteSlots(); @@ -331,12 +331,12 @@ public: }; /// draws picture with creature on background, use Animated=true to get animation -class CCreaturePic : public CIntObject +class CCreaturePic : public CIntObject { private: CPicture *bg; //background CCreatureAnim *anim; //displayed animation - + public: CCreaturePic(int x, int y, const CCreature *cre, bool Big=true, bool Animated=true); //c-tor ~CCreaturePic(); //d-tor @@ -441,33 +441,45 @@ public: /// Town portal, castle gate window class CObjectListWindow : public CIntObject { -public: + class CItem : public CIntObject + { + CObjectListWindow *parent; + CLabel *text; + CPicture *border; + public: + const size_t index; + CItem(CObjectListWindow *parent, size_t id, std::string text); + + void select(bool on); + void clickLeft(tribool down, bool previousState); + }; boost::function onSelect;//called when OK button is pressed, returns id of selected item. - std::string title,descr;//text for title and description + CLabel * title; + CLabel * descr; + CListBox *list; CPicture *bg; //background - CSlider *slider; CPicture *titleImage;//title image (castle gate\town portal picture) CAdventureMapButton *ok, *exit; - std::vector areas;//areas for each visible item - std::vector items;//id of all items present in list - int selected;//currently selected item - int length;//size of list (=9) - bool init;//true = initialization completed + std::vector< std::pair > items;//all items present in list + void init(CPicture * titlePic, std::string _title, std::string _descr); +public: + size_t selected;//index of currently selected item /// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item + /// Image can be NULL + ///item names will be taken from map objects CObjectListWindow(const std::vector &_items, CPicture * titlePic, std::string _title, std::string _descr, - boost::function Callback, int initState=-1); //c-tor - ~CObjectListWindow(); //d-tor + boost::function Callback); + CObjectListWindow(const std::vector &_items, CPicture * titlePic, std::string _title, std::string _descr, + boost::function Callback); - void elementSelected();//call callback and exit - void moveList(int which);//called when slider moves - void clickLeft(tribool down, bool previousState); //call-in - void keyPressed (const SDL_KeyboardEvent & key); //call-in - void show(SDL_Surface * to); - void showAll(SDL_Surface * to); + CIntObject *genItem(size_t index); + void elementSelected();//call callback and close this window + void changeSelection(size_t which); + void keyPressed (const SDL_KeyboardEvent & key); }; class CArtifactHolder : public virtual CIntObject @@ -501,10 +513,10 @@ public: }; class CTradeableItem : public CIntObject { - const CArtifactInstance *hlp; //holds ptr to artifact instance id type artifact + const CArtifactInstance *hlp; //holds ptr to artifact instance id type artifact public: EType type; - int id; + int id; int serial; bool left; std::string subtitle; //empty if default @@ -563,7 +575,7 @@ public: virtual void selectionChanged(bool side) = 0; //true == left virtual Point selectionOffset(bool Left) const = 0; virtual std::string selectionSubtitle(bool Left) const = 0; - virtual void garrisonChanged() = 0; + virtual void garrisonChanged() = 0; virtual void artifactsChanged(bool left) = 0; }; @@ -625,7 +637,7 @@ public: Point selectionOffset(bool Left) const; std::string selectionSubtitle(bool Left) const; - void garrisonChanged(); + void garrisonChanged(); void artifactsChanged(bool left); void calcTotalExp(); void setExpToLevel(); @@ -639,14 +651,28 @@ public: class CSystemOptionsWindow : public CIntObject { private: - SDL_Surface * background; //background of window + CLabel *title; + CLabelGroup *leftGroup; + CLabelGroup *rightGroup; + CPicture * bg; //background of window CAdventureMapButton *load, *save, *restart, *mainMenu, *quitGame, *backToMap; //load and restart are not used yet CHighlightableButtonsGroup * heroMoveSpeed; CHighlightableButtonsGroup * mapScrollSpeed; CHighlightableButtonsGroup * musicVolume, * effectsVolume; -public: - CSystemOptionsWindow(const SDL_Rect & pos, CPlayerInterface * owner); //c-tor - ~CSystemOptionsWindow(); //d-tor + + //CHighlightableButton * showPath; + CHighlightableButton * showReminder; + //CHighlightableButton * quickCombat; + //CHighlightableButton * videoSubs; + CHighlightableButton * newCreatureWin; + CHighlightableButton * fullscreen; + + CAdventureMapButton *gameResButton; + + void setMusicVolume( int newVolume ); + void setSoundVolume( int newVolume ); + void setHeroMoveSpeed( int newSpeed ); + void setMapScrollingSpeed( int newSpeed ); //functions bound to buttons void bsavef(); //save game @@ -654,9 +680,18 @@ public: void breturnf(); //return to game void bmainmenuf(); //return to main menu + //functions for checkboxes + void toggleReminder(bool on); + void toggleCreatureWin(bool on); + void toggleFullscreen(bool on); + + void selectGameRes(bool pregame); + void setGameRes(bool pregame, int index); + void pushSDLEvent(int type, int usercode); - void showAll(SDL_Surface * to); +public: + CSystemOptionsWindow(const SDL_Rect & pos, CPlayerInterface * owner); //c-tor }; class CTavernWindow : public CIntObject @@ -740,7 +775,7 @@ class MoraleLuckBox : public LRClickableAreaWTextComp public: bool morale; //true if morale, false if luck bool small; - + void set(const IBonusBearer *node); void showAll(SDL_Surface * to); @@ -753,9 +788,9 @@ class CHeroArea: public CIntObject { public: const CGHeroInstance * hero; - + CHeroArea(int x, int y, const CGHeroInstance * _hero); - + void clickLeft(tribool down, bool previousState); void clickRight(tribool down, bool previousState); void hover(bool on); @@ -888,7 +923,7 @@ class CGarrisonWindow : public CWindowWithGarrison { public: CPicture *bg; //background surface - CLabel *title; + CLabel *title; CAdventureMapButton *quit; void close(); diff --git a/client/UIFramework/CGuiHandler.cpp b/client/UIFramework/CGuiHandler.cpp index 36e963ec8..8818944e9 100644 --- a/client/UIFramework/CGuiHandler.cpp +++ b/client/UIFramework/CGuiHandler.cpp @@ -340,7 +340,7 @@ void CGuiHandler::run() setThreadName(-1, "CGuiHandler::run"); try { - if (conf.cc.fullscreen) + if (settings["video"]["fullscreen"].Bool()) CCS->curh->centerCursor(); mainFPSmng->init(); // resets internal clock, needed for FPS manager diff --git a/client/UIFramework/CIntObjectClasses.cpp b/client/UIFramework/CIntObjectClasses.cpp index da21e2b4f..c4d906d82 100644 --- a/client/UIFramework/CIntObjectClasses.cpp +++ b/client/UIFramework/CIntObjectClasses.cpp @@ -941,6 +941,16 @@ void CListBox::reset() updatePositions(); } +void CListBox::scrollTo(size_t which) +{ + //scroll up + if (first > which) + moveToPos(which); + //scroll down + else if (first + items.size() <= which) + moveToPos(which - items.size()); +} + void CListBox::moveToPos(size_t which) { //Calculate new position @@ -1193,6 +1203,16 @@ void CLabel::setTxt(const std::string &Txt) } } +CLabelGroup::CLabelGroup(EFonts Font, EAlignment Align, const SDL_Color &Color): + font(Font), align(Align), color(Color) +{}; + +void CLabelGroup::add(int x, int y, const std::string &text) +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + new CLabel(x, y, font, align, color, text); +}; + CTextBox::CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= TOPLEFT*/, const SDL_Color &Color /*= Colors::Cornsilk*/) :CLabel(rect.x, rect.y, Font, Align, Color, Text), sliderStyle(SliderStyle), slider(NULL) { diff --git a/client/UIFramework/CIntObjectClasses.h b/client/UIFramework/CIntObjectClasses.h index 64c931eb0..13afe569e 100644 --- a/client/UIFramework/CIntObjectClasses.h +++ b/client/UIFramework/CIntObjectClasses.h @@ -274,7 +274,10 @@ public: //return currently active items std::list< CIntObject * > getItems(); - //scroll list + //scroll list to make item which visible + void scrollTo(size_t which); + + //scroll list to specified position void moveToPos(size_t which); void moveToNext(); void moveToPrev(); @@ -316,6 +319,18 @@ public: CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::Cornsilk, const std::string &Text = ""); }; +//Small helper class to manage group of similar labels +class CLabelGroup : public CIntObject +{ + std::list labels; + EFonts font; + EAlignment align; + const SDL_Color &color; +public: + CLabelGroup(EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::Cornsilk); + void add(int x=0, int y=0, const std::string &text = ""); +}; + /// a multi-line label that tries to fit text with given available width and height; if not possible, it creates a slider for scrolling text class CTextBox : public CLabel diff --git a/config/defaultSettings.json b/config/defaultSettings.json new file mode 100644 index 000000000..da8ea794f --- /dev/null +++ b/config/defaultSettings.json @@ -0,0 +1,142 @@ +// This is schema for checking game settings from settings.json +// Any new settings should be added in this file for correct serialization and initialization +{ + "general" : { + "type" : "object", + "properties" : { + "classicCreatureWindow" : { + "type" : "bool", + "default" : false + }, + "playerName" : { + "type":"string", + "default" : "player" + }, + "showfps" : { + "type" : "bool", + "default" : false + }, + "music" : { + "type" : "number", + "default" : 88 + }, + "sound" : { + "type" : "number", + "default" : 88 + } + }, + "default" : {} + }, + "video" : { + "type" : "object", + "properties" : { + "gameRes" : { + "type" : "object", + "properties" : { + "width" : { "type" : "number" }, + "height" : { "type" : "number" } + }, + "default": {"width" : 800, "height": 600 } + }, + "menuRes" : { + "type" : "object", + "properties" : { + "width" : { "type" : "number" }, + "height" : { "type" : "number" } + }, + "default": {"width" : 800, "height": 600 } + }, + "screenRes" : { + "type" : "object", + "properties" : { + "width" : { "type" : "number" }, + "height" : { "type" : "number" } + }, + "default": {"width" : 0, "height": 0 } + }, + "bitsPerPixel" : { + "type" : "number", + "default" : 24 + }, + "fullscreen" : { + "type" : "bool", + "default" : false + } + }, + "default" : {} + }, + "adventure" : { + "type" : "object", + "properties" : { + "heroSpeed" : { + "type" : "number", + "default" : 2 + }, + "enemySpeed" : { + "type" : "number", + "default" : 2 + }, + "scrollSpeed" : { + "type" : "number", + "default" : 1 + }, + "heroReminder" : { + "type" : "bool", + "default" : true + } + }, + "default" : {} + }, + "battle" : { + "type" : "object", + "properties" : { + "animationSpeed" : { + "type" : "number", + "default" : 2 + }, + "mouseShadow" : { + "type":"bool", + "default" : true + }, + "cellBorders" : { + "type" : "bool", + "default" : false + }, + "stackRange" : { + "type" : "bool", + "default" : true + }, + "showQueue" : { + "type" : "bool", + "default" : true + } + }, + "default" : {} + }, + "server" : { + "type" : "object", + "properties" : { + "server" : { + "type":"string", + "default" : "127.0.0.1" + }, + "port" : { + "type" : "number", + "default" : 3030 + }, + "localInformation" : { + "type" : "number", + "default" : 2 + }, + "playerAI" : { + "type" : "string", + "default" : "GeniusAI" + }, + "neutralAI" : { + "type" : "string", + "default" : "StupidAI" + } + }, + "default" : {} + } +} diff --git a/config/settings.txt b/config/settings.txt index 5e498fa9c..11c107da6 100644 --- a/config/settings.txt +++ b/config/settings.txt @@ -1,3 +1,8 @@ +THIS FILE IS OUTDATED +- to change setting including resolution: use in-game menu +- to change setting manually: file settings.json +- to add new options or to modify default values: file defaultSettings.json + //DO NOT EDIT!!! //DO NOT READ! clientSettings diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index 6aa8f1d3b..5dd86e7e7 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -69,6 +69,38 @@ JsonNode & JsonNode::operator =(JsonNode node) return *this; } +bool JsonNode::operator == (const JsonNode &other) const +{ + if (getType() == other.getType()) + { + switch(type) + { + break; case DATA_NULL: return true; + break; case DATA_BOOL: return Bool() == other.Bool(); + break; case DATA_FLOAT: return Float() == other.Float(); + break; case DATA_STRING: return String() == other.String(); + break; case DATA_VECTOR: return Vector() == other.Vector(); + break; case DATA_STRUCT: return Struct() == other.Struct(); + } + } + return false; +} + +bool JsonNode::operator != (const JsonNode &other) const +{ + return !(*this == other); +} + +void JsonNode::minimize(const JsonNode& schema) +{ + JsonValidator validator(*this, schema, true); +} + +void JsonNode::validate(const JsonNode& schema) +{ + JsonValidator validator(*this, schema, false); +} + JsonNode::JsonType JsonNode::getType() const { return type; @@ -687,6 +719,11 @@ bool JsonValidator::validateType(JsonNode &node, const JsonNode &schema, JsonNod else node = defaultValue; } + if (minimize && node == schema["default"]) + { + node.setType(JsonNode::DATA_NULL); + return false; + } if (type != node.getType()) { @@ -709,18 +746,13 @@ bool JsonValidator::validateNode(JsonNode &node, const JsonNode &schema, const s currentPath.push_back(name); JsonNode::JsonType type = JsonNode::DATA_NULL; - if (!validateSchema(type, schema)) + if (!validateSchema(type, schema) + || !validateType(node, schema, type)) { + node.setType(JsonNode::DATA_NULL); currentPath.pop_back(); return false; } - - if (!validateType(node, schema, type)) - { - currentPath.pop_back(); - return false; - } - currentPath.pop_back(); return true; } @@ -732,12 +764,16 @@ bool JsonValidator::validateItems(JsonNode &node, const JsonNode &schema) if (!validateSchema(type, schema)) return false; + bool result = true; BOOST_FOREACH(JsonNode &entry, node.Vector()) { if (!validateType(entry, schema, type)) - return false; + { + result = false; + entry.setType(JsonNode::DATA_NULL); + } } - return true; + return result; } //Checks "propertries" entry from schema (type-specific check for Struct) @@ -752,29 +788,40 @@ bool JsonValidator::validateProperties(JsonNode &node, const JsonNode &schema) while (nodeIter != node.Struct().end() && schemaIter != schema.Struct().end()) { - std::string current = std::min(nodeIter->first, schemaIter->first); - validateNode(node[current], schema[current], current); - - if (nodeIter->first < schemaIter->first) - nodeIter++; - else - if (schemaIter->first < nodeIter->first) - schemaIter++; - else + if (nodeIter->first < schemaIter->first) //No schema for entry { - nodeIter++; + validateNode(nodeIter->second, JsonNode::nullNode, nodeIter->first); + + JsonMap::iterator toRemove = nodeIter++; + node.Struct().erase(toRemove); + } + else + if (schemaIter->first < nodeIter->first) //No entry + { + if (!validateNode(node[schemaIter->first], schemaIter->second, schemaIter->first)) + node.Struct().erase(schemaIter->first); + schemaIter++; + } + else //both entry and schema are present + { + JsonMap::iterator current = nodeIter++; + if (!validateNode(current->second, schemaIter->second, current->first)) + node.Struct().erase(current); + schemaIter++; } } while (nodeIter != node.Struct().end()) { - validateNode(nodeIter->second, JsonNode(), nodeIter->first); - nodeIter++; + validateNode(nodeIter->second, JsonNode::nullNode, nodeIter->first); + JsonMap::iterator toRemove = nodeIter++; + node.Struct().erase(toRemove); } while (schemaIter != schema.Struct().end()) { - validateNode(node[schemaIter->first], schemaIter->second, schemaIter->first); + if (!validateNode(node[schemaIter->first], schemaIter->second, schemaIter->first)) + node.Struct().erase(schemaIter->first); schemaIter++; } return true; @@ -792,14 +839,15 @@ bool JsonValidator::addMessage(const std::string &message) return false; } -JsonValidator::JsonValidator(JsonNode &root) +JsonValidator::JsonValidator(JsonNode &root, bool Minimize): + minimize(Minimize) { JsonNode schema; schema.swap(root["schema"]); + root.Struct().erase("schema"); if (!schema.isNull()) { - root.Struct().erase("schema"); validateProperties(root, schema); } //This message is quite annoying now - most files do not have schemas. May be re-enabled later @@ -809,3 +857,12 @@ JsonValidator::JsonValidator(JsonNode &root) //TODO: better way to show errors (like printing file name as well) tlog3< currentPath; // path from root node to current one + bool minimize; bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type); bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema); @@ -170,5 +179,8 @@ class JsonValidator bool addMessage(const std::string &message); public: - JsonValidator(JsonNode &root); + // validate node with "schema" entry + JsonValidator(JsonNode &root, bool minimize=false); + // validate with external schema + JsonValidator(JsonNode &root, const JsonNode &schema, bool minimize=false); };