1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

- setting system: replaced settings.txt + sysopt.bin with json-based system (defaultSetting.json + settings.json)

- some work on system settings window
- new menu for selecting resolution (reused town portal graphics), can be opened from system settings
This commit is contained in:
Ivan Savenko 2012-01-12 15:23:00 +00:00
parent 046e54563c
commit 86e7d96b39
25 changed files with 1179 additions and 758 deletions

View File

@ -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();
}
}

View File

@ -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<ui16> shaded = spToCast.rangeInHexes(b, schoolLevel);
for(std::set<ui16>::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<BattleHex, int> *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<Cimage> &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<BattleHex> 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();

View File

@ -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);

View File

@ -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<CComponent*>(), 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<CComponent*>(), 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<CComponent*>(), 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<const CGObjectInstance *> objs = LOCPLINT->cb->getBlockingObjs(tile);
std::vector<const CGObjectInstance *> 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<const CGTownInstance*>(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<const CGGarrison*>(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
}

View File

@ -1,22 +1,11 @@
#include "StdInc.h"
#include <boost/version.hpp>
#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 <boost/spirit/include/classic.hpp>
using namespace boost::spirit::classic;
#else
#include <boost/spirit.hpp>
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<typename Accessor>
SettingsStorage::NodeAccessor<Accessor>::NodeAccessor(SettingsStorage & _parent, std::vector<std::string> _path):
parent(_parent),
path(_path)
{
std::string txt;
lerror(const std::string & TXT):txt(TXT){};
void operator()() const
{
tlog1 << txt << std::endl;
}
template<typename IteratorT>
void operator()(IteratorT t1, IteratorT t2) const
{
tlog1 << txt << std::endl;
}
};
struct lerror2
}
template<typename Accessor>
SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator [](std::string nextNode) const
{
std::string txt;
lerror2(const std::string & TXT):txt(TXT){};
template<typename IteratorT>
void operator()(IteratorT t1, IteratorT t2) const
{
std::string txt2(t1,t2);
tlog1 << txt << txt2 << std::endl;
}
};
struct SettingsGrammar : public grammar<SettingsGrammar>
std::vector<std::string> newPath = path;
newPath.push_back(nextNode);
return NodeAccessor(parent, newPath);
}
template<typename Accessor>
SettingsStorage::NodeAccessor<Accessor>::operator Accessor() const
{
template <typename ScannerT>
struct definition
{
rule<ScannerT> r, clientOption, clientOptionsSequence, ClientSettings;
return Accessor(parent, path);
}
template<typename Accessor>
SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator () (std::vector<std::string> _path)
{
std::vector<std::string> 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<ScannerT> const& start() const { return r; }
};
};
struct CommentsGrammar : public grammar<CommentsGrammar>
SettingsStorage::SettingsStorage():
write(NodeAccessor<Settings>(*this, std::vector<std::string>() )),
listen(NodeAccessor<SettingsListener>(*this, std::vector<std::string>() ))
{
template <typename ScannerT>
struct definition
{
rule<ScannerT> comment;
definition(CommentsGrammar const& self)
{
comment = comment_p("//") | comment_p("/*","*/") | space_p;
BOOST_SPIRIT_DEBUG_RULE(comment);
}
rule<ScannerT> 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<std::string> &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<std::string> path)
{
JsonNode *node = &config;
BOOST_FOREACH(std::string& value, path)
node = &(*node)[value];
return *node;
}
Settings SettingsStorage::get(std::vector<std::string> path)
{
return Settings(*this, path);
}
const JsonNode& SettingsStorage::operator [](std::string value)
{
return config[value];
}
SettingsListener::SettingsListener(SettingsStorage &_parent, const std::vector<std::string> &_path):
parent(_parent),
path(_path)
{
parent.listeners.insert(this);
}
SettingsListener::~SettingsListener()
{
parent.listeners.erase(this);
}
void SettingsListener::nodeInvalidated(const std::vector<std::string> 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<void(const JsonNode&)> _callback)
{
callback = _callback;
}
Settings::Settings(SettingsStorage &_parent, const std::vector<std::string> &_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<SettingsListener>;
template struct SettingsStorage::NodeAccessor<Settings>;
static void setButton(ButtonInfo &button, const JsonNode &g)
{
@ -145,29 +193,6 @@ CConfigHandler::~CConfigHandler(void)
void config::CConfigHandler::init()
{
std::vector<char> 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<char>(ifs),std::istream_iterator<char>(),std::back_inserter(settings));
std::vector<char>::const_iterator first = settings.begin(), last = settings.end();
SettingsGrammar sg;
BOOST_SPIRIT_DEBUG_NODE(sg);
CommentsGrammar cg;
BOOST_SPIRIT_DEBUG_NODE(cg);
parse_info<std::vector<char>::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());
}

View File

@ -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<typename Accessor>
struct NodeAccessor
{
SettingsStorage & parent;
std::vector<std::string> path;
NodeAccessor(SettingsStorage & _parent, std::vector<std::string> _path);
NodeAccessor<Accessor> operator [] (std::string nextNode) const;
NodeAccessor<Accessor> operator () (std::vector<std::string> _path);
operator Accessor() const;
};
std::set<SettingsListener*> listeners;
JsonNode config;
JsonNode & getNode(std::vector<std::string> path);
// Calls all required listeners
void invalidateNode(const std::vector<std::string> &changedPath);
Settings get(std::vector<std::string> path);
public:
// Initialize config structure
SettingsStorage();
void init();
// Get write access to config node at path
const NodeAccessor<Settings> write;
// Get access to listener at path
const NodeAccessor<SettingsListener> 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<std::string> path;
// Callback
boost::function<void(const JsonNode&)> callback;
SettingsListener(SettingsStorage &_parent, const std::vector<std::string> &_path);
// Executes callback if changedpath begins with path
void nodeInvalidated(const std::vector<std::string> changedPath);
public:
~SettingsListener();
// assign callback function
void operator()(boost::function<void(const JsonNode&)> _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<std::string> path;
JsonNode &node;
JsonNode copy;
//Get access to node pointed by path
Settings(SettingsStorage &_parent, const std::vector<std::string> &_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<std::pair<int,int>, GUIOptions > guiOptions;
typedef std::map<std::pair<int,int>, 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;

View File

@ -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<void()> Upg, boost::function<void()> 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);

View File

@ -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<SDL_Event*> 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: "<<pomtime.getDiff()<<std::endl;
tlog0<<"Initializing screen and sound handling: "<<tmh.getDiff()<<std::endl;
@ -248,12 +230,13 @@ int main(int argc, char** argv)
atexit(dispose);
tlog0 <<"Creating console and logfile: "<<pomtime.getDiff() << std::endl;
settings.init();
conf.init();
tlog0 <<"Loading settings: "<<pomtime.getDiff() << std::endl;
tlog0 << NAME << std::endl;
srand ( time(NULL) );
CCS = new CClientState;
CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler etc.)
@ -264,7 +247,11 @@ int main(int argc, char** argv)
}
atexit(SDL_Quit);
setScreenRes(conf.cc.pregameResx, conf.cc.pregameResy, conf.cc.bpp, conf.cc.fullscreen);
const JsonNode& video = settings["video"];
const JsonNode& res = video["menuRes"];
setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool());
tlog0 <<"\tInitializing screen: "<<pomtime.getDiff() << std::endl;
// Initialize video
@ -289,8 +276,9 @@ int main(int argc, char** argv)
if(!vm.count("battle"))
{
gOnlyAI = vm.count("onlyAI");
conf.cc.autoSkip = vm.count("autoSkip");
conf.cc.oneGoodAI = vm.count("oneGoodAI");
Settings session = settings.write["session"];
session["autoSkip"].Bool() = vm.count("autoSkip");
session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
if(!vm.count("start"))
@ -318,7 +306,8 @@ void printInfoAboutIntObject(const CIntObject *obj, int level)
int tabs = level;
while(tabs--) tlog4 << '\t';
tlog4 << typeid(*obj).name() << " *** " << (obj->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++<i; j++); //move j to the i-th resolution info
conf.cc.resx = conf.cc.screenx = j->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<boost::recursive_mutex> 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<int, PlayerSettings>::iterator it = options->playerInfos.begin();
for(std::map<int, PlayerSettings>::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();

View File

@ -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;

View File

@ -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 )

View File

@ -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<soundBase::soundID, Mix_Chunk *> 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<MusicEntry> current;
std::auto_ptr<MusicEntry> next;

View File

@ -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<bool>(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 <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, const int version )
{
h & playerID;
h & sysOpts;
h & spellbookSettings;
//sleeping heroes
@ -1099,7 +1099,7 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
if (!h.saving)
{
const CGHeroInstance *hero = cb->getHero(hid);
sleepingHeroes += hero;
sleepingHeroes += hero;
}
}
@ -1119,7 +1119,7 @@ template <typename Handler> 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<CSaveFile> &h, const int version )
void CPlayerInterface::serialize( CISer<CLoadFile> &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<CInfoWindow *>(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<CInfoWindow *>(GH.topInt()))
iw->close();

View File

@ -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 <typename Handler> 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;

View File

@ -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<ui32, std::string> 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<ui32, std::string> *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()

View File

@ -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()
{

View File

@ -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<int, PlayerSettings>::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: "<<th.getDiff()<<std::endl;
@ -668,7 +670,7 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
{
serverThread = NULL;
shared = NULL;
port = boost::lexical_cast<std::string>(conf.cc.port);
port = boost::lexical_cast<std::string>(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<std::string>(conf.cc.port),
ret = new CConnection( host.size() ? host : settings["server"]["server"].String(),
port.size() ? port : boost::lexical_cast<std::string>(settings["server"]["port"].Float()),
NAME);
}
catch(...)

File diff suppressed because it is too large Load Diff

View File

@ -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<CGarrisonSlot*> &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<void(int)> 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<Rect> areas;//areas for each visible item
std::vector<int> 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<int, std::string> > 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<int> &_items, CPicture * titlePic, std::string _title, std::string _descr,
boost::function<void(int)> Callback, int initState=-1); //c-tor
~CObjectListWindow(); //d-tor
boost::function<void(int)> Callback);
CObjectListWindow(const std::vector<std::string> &_items, CPicture * titlePic, std::string _title, std::string _descr,
boost::function<void(int)> 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();

View File

@ -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

View File

@ -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)
{

View File

@ -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<CLabel*> 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

142
config/defaultSettings.json Normal file
View File

@ -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" : {}
}
}

View File

@ -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

View File

@ -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<<errors;
}
JsonValidator::JsonValidator(JsonNode &root, const JsonNode &schema, bool Minimize):
minimize(Minimize)
{
validateProperties(root, schema);
if (schema.isNull())
addMessage("Schema not found!");
tlog3<<errors;
}

View File

@ -47,6 +47,14 @@ public:
void swap(JsonNode &b);
JsonNode& operator =(JsonNode node);
bool operator == (const JsonNode &other) const;
bool operator != (const JsonNode &other) const;
//removes all nodes that are identical to default entry in schema
void minimize(const JsonNode& schema);
//check schema
void validate(const JsonNode& schema);
//Convert node to another type. Converting to NULL will clear all data
void setType(JsonType Type);
JsonType getType() const;
@ -161,6 +169,7 @@ class JsonValidator
{
std::string errors; // Contains description of all encountered errors
std::list<std::string> 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);
};