mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-14 02:33:51 +02:00
- fixed #808
- Implemented Json validator and schema for buildings.json - several fixes for Json writing - fixed several gcc warnings
This commit is contained in:
parent
7b1ede449d
commit
89bd7e273d
@ -1184,8 +1184,8 @@ void CBattleInterface::addNewAnim(CBattleAnimation * anim)
|
|||||||
|
|
||||||
CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen)
|
CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen)
|
||||||
: queue(NULL), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0),
|
: queue(NULL), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0),
|
||||||
activeStack(NULL), stackToActivate(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1), previouslyHoveredHex(-1), spellSelMode(NO_LOCATION),
|
activeStack(NULL), stackToActivate(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1), previouslyHoveredHex(-1),
|
||||||
currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL), stackCanCastSpell(false), spellDestSelectMode(false), spellToCast(NULL),
|
currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL), stackCanCastSpell(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL),
|
||||||
siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0), givenCommand(NULL),
|
siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0), givenCommand(NULL),
|
||||||
myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL)
|
myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL)
|
||||||
|
|
||||||
@ -2043,7 +2043,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
|
|||||||
const CSpell * spell = CGI->spellh->spells[creatureSpellToCast];
|
const CSpell * spell = CGI->spellh->spells[creatureSpellToCast];
|
||||||
if (curInt->cb->battleCanCastThisSpell(spell, THex(myNumber)) == SpellCasting::OK)
|
if (curInt->cb->battleCanCastThisSpell(spell, THex(myNumber)) == SpellCasting::OK)
|
||||||
{
|
{
|
||||||
if (spell->positiveness > -1 && ourStack || spell->positiveness < 1 && !ourStack)
|
if ((spell->positiveness > -1 && ourStack) || (spell->positiveness < 1 && !ourStack))
|
||||||
{
|
{
|
||||||
CCS->curh->changeGraphic(3, 0);
|
CCS->curh->changeGraphic(3, 0);
|
||||||
stackCastsSpell = true;
|
stackCastsSpell = true;
|
||||||
@ -2869,7 +2869,7 @@ void CBattleInterface::hexLclicked(int whichOne)
|
|||||||
const CSpell * spell = CGI->spellh->spells[creatureSpellToCast];
|
const CSpell * spell = CGI->spellh->spells[creatureSpellToCast];
|
||||||
if (curInt->cb->battleCanCastThisSpell(spell, THex(whichOne)) == SpellCasting::OK)
|
if (curInt->cb->battleCanCastThisSpell(spell, THex(whichOne)) == SpellCasting::OK)
|
||||||
{
|
{
|
||||||
if (spell->positiveness > -1 && ourStack || spell->positiveness < 1 && !ourStack)
|
if ((spell->positiveness > -1 && ourStack) || (spell->positiveness < 1 && !ourStack))
|
||||||
{
|
{
|
||||||
giveCommand(BattleAction::MONSTER_SPELL, whichOne, actSt->ID, creatureSpellToCast);
|
giveCommand(BattleAction::MONSTER_SPELL, whichOne, actSt->ID, creatureSpellToCast);
|
||||||
}
|
}
|
||||||
|
@ -2052,122 +2052,124 @@ void CSplitWindow::clickLeft(tribool down, bool previousState)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCreInfoWindow::show(SDL_Surface *to)
|
||||||
void CCreInfoWindow::show(SDL_Surface * to)
|
|
||||||
{
|
{
|
||||||
blitAt(*bitmap,pos.x,pos.y,to);
|
CIntObject::show(to);
|
||||||
anim->show(to);
|
creatureCount->showAll(to);
|
||||||
if(count.size())
|
|
||||||
printTo(count.c_str(),pos.x+114,pos.y+174,FONT_TIMES,zwykly,to);
|
|
||||||
if(upgrade)
|
|
||||||
upgrade->showAll(to);
|
|
||||||
if(dismiss)
|
|
||||||
dismiss->showAll(to);
|
|
||||||
if(ok)
|
|
||||||
ok->showAll(to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui)
|
CCreInfoWindow::CCreInfoWindow(const CStackInstance &stack, bool LClicked, boost::function<void()> upgradeFunc, boost::function<void()> dismissFunc, UpgradeInfo *upgradeInfo)
|
||||||
: type(Type), dsm(Dsm), dismiss(0), upgrade(0), ok(0)
|
|
||||||
{
|
{
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
init(st.type, &st, dynamic_cast<const CGHeroInstance*>(st.armyObj), st.count);
|
init(stack.type, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj), stack.count, LClicked);
|
||||||
|
|
||||||
//print abilities text - if r-click popup
|
//additional buttons if opened with left click
|
||||||
if(type)
|
if(LClicked)
|
||||||
{
|
{
|
||||||
if(Upg && ui)
|
boost::function<void()> closeFunc = boost::bind(&CCreInfoWindow::close,this);
|
||||||
|
|
||||||
|
if(upgradeFunc && upgradeInfo)
|
||||||
{
|
{
|
||||||
TResources upgradeCost = ui->cost[0] * st.count;
|
TResources upgradeCost = upgradeInfo->cost[0] * stack.count;
|
||||||
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
|
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
|
||||||
{
|
{
|
||||||
BLOCK_CAPTURING;
|
BLOCK_CAPTURING;
|
||||||
upgResCost.push_back(new SComponent(SComponent::resource, i->resType, i->resVal));
|
upgResCost.push_back(new SComponent(SComponent::resource, i->resType, i->resVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost))
|
CFunctionList<void()> onUpgrade;
|
||||||
{
|
onUpgrade += upgradeFunc;
|
||||||
CFunctionList<void()> fs;
|
onUpgrade += closeFunc;
|
||||||
fs += Upg;
|
|
||||||
fs += boost::bind(&CCreInfoWindow::close,this);
|
|
||||||
CFunctionList<void()> cfl;
|
|
||||||
cfl = boost::bind(&CPlayerInterface::showYesNoDialog, LOCPLINT, CGI->generaltexth->allTexts[207], boost::ref(upgResCost), fs, 0, true);
|
|
||||||
upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,76,237,"IVIEWCR.DEF",SDLK_u);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,boost::function<void()>(),76,237,"IVIEWCR.DEF");
|
|
||||||
upgrade->callback.funcs.clear();
|
|
||||||
upgrade->setOffset(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
boost::function<void()> dialog = boost::bind(&CPlayerInterface::showYesNoDialog,
|
||||||
|
LOCPLINT,
|
||||||
|
CGI->generaltexth->allTexts[207],
|
||||||
|
boost::ref(upgResCost),
|
||||||
|
onUpgrade, 0, false);
|
||||||
|
|
||||||
|
upgrade = new AdventureMapButton("", CGI->generaltexth->zelp[446].second, dialog, 76, 237, "IVIEWCR", SDLK_u);
|
||||||
|
upgrade->block(!LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost));
|
||||||
}
|
}
|
||||||
if(Dsm)
|
|
||||||
|
if(dismissFunc)
|
||||||
{
|
{
|
||||||
CFunctionList<void()> fs[2];
|
CFunctionList<void()> onDismiss;
|
||||||
//on dismiss confirmed
|
onDismiss += dismissFunc;
|
||||||
fs[0] += Dsm; //dismiss
|
onDismiss += closeFunc;
|
||||||
fs[0] += boost::bind(&CCreInfoWindow::close,this);//close this window
|
|
||||||
CFunctionList<void()> cfl;
|
boost::function<void()> dialog = boost::bind(&CPlayerInterface::showYesNoDialog,
|
||||||
cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector<SComponent*>(),fs[0],fs[1],true);
|
LOCPLINT,
|
||||||
dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,21,237,"IVIEWCR2.DEF",SDLK_d);
|
CGI->generaltexth->allTexts[12],
|
||||||
|
std::vector<SComponent*>(),
|
||||||
|
onDismiss, 0, true);
|
||||||
|
|
||||||
|
dismiss = new AdventureMapButton("", CGI->generaltexth->zelp[445].second, dialog, 21, 237, "IVIEWCR2",SDLK_d);
|
||||||
}
|
}
|
||||||
ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),216,237,"IOKAY.DEF",SDLK_RETURN);
|
|
||||||
|
ok = new AdventureMapButton("", CGI->generaltexth->zelp[445].second,
|
||||||
|
boost::bind(&CCreInfoWindow::close,this), 216, 237, "IOKAY.DEF", SDLK_RETURN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCreInfoWindow::CCreInfoWindow(int creatureID, bool LClicked, int creatureCount)
|
||||||
|
|
||||||
CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount)
|
|
||||||
: type(Type), dismiss(0), upgrade(0), ok(0)
|
|
||||||
{
|
{
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
const CCreature *cre = CGI->creh->creatures[Cid];
|
const CCreature *creature = CGI->creh->creatures[creatureID];
|
||||||
init(cre, NULL, NULL, creatureCount);
|
init(creature, NULL, NULL, creatureCount, LClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
CCreInfoWindow::CCreInfoWindow(const CStack &st, int Type /*= 0*/)
|
CCreInfoWindow::CCreInfoWindow(const CStack &stack, bool LClicked)
|
||||||
: type(Type), dismiss(0), upgrade(0), ok(0)
|
|
||||||
{
|
{
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
init(st.getCreature(), &st, st.getMyHero(), st.count);
|
init(stack.getCreature(), &stack, stack.getMyHero(), stack.count, LClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCreInfoWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
|
CCreInfoWindow::~CCreInfoWindow()
|
||||||
{
|
{
|
||||||
printAt(text, 155, 48 + nr*19, FONT_SMALL, zwykly, *bitmap);
|
BOOST_FOREACH(SComponent* object, upgResCost)
|
||||||
|
delete object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCreInfoWindow::printLine(int position, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
|
||||||
|
{
|
||||||
|
infoTexts[position].first = new CLabel(155, 48 + position*19, FONT_SMALL, TOPLEFT, zwykly, text);
|
||||||
|
std::string valueStr;
|
||||||
|
|
||||||
std::string hlp;
|
|
||||||
if(range && baseVal != val)
|
if(range && baseVal != val)
|
||||||
hlp = boost::str(boost::format("%d - %d") % baseVal % val);
|
valueStr = boost::str(boost::format("%d - %d") % baseVal % val);
|
||||||
else if(baseVal != val && val>=0)
|
|
||||||
hlp = boost::str(boost::format("%d (%d)") % baseVal % val);
|
|
||||||
else
|
|
||||||
hlp = boost::lexical_cast<std::string>(baseVal);
|
|
||||||
|
|
||||||
printTo(hlp, 276, 61 + nr*19, FONT_SMALL, zwykly, *bitmap);
|
else if(baseVal != val && val>=0)
|
||||||
|
valueStr = boost::str(boost::format("%d (%d)") % baseVal % val);
|
||||||
|
|
||||||
|
else
|
||||||
|
valueStr = boost::lexical_cast<std::string>(baseVal);
|
||||||
|
|
||||||
|
infoTexts[position].second = new CLabel(276, 63 + position*19, FONT_SMALL, BOTTOMRIGHT, zwykly, valueStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//void CCreInfoWindow::init(const CCreature *cre, const CStackInstance *stack, int creatureCount)
|
void CCreInfoWindow::init(const CCreature *creature, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int count, bool LClicked)
|
||||||
void CCreInfoWindow::init(const CCreature *cre, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int creatureCount)
|
|
||||||
{
|
{
|
||||||
c = cre;
|
used = 0;
|
||||||
if(!stackNode) stackNode = c;
|
if (!LClicked)
|
||||||
|
used |= RCLICK;
|
||||||
|
|
||||||
bitmap = new CPicture("CRSTKPU.bmp");
|
if(!stackNode)
|
||||||
bitmap->colorizeAndConvert(LOCPLINT->playerID);
|
stackNode = creature;
|
||||||
pos = bitmap->center();
|
|
||||||
|
|
||||||
anim = new CCreaturePic(21, 48, c);
|
background = new CPicture("CRSTKPU");
|
||||||
|
background->colorize(LOCPLINT->playerID);
|
||||||
|
pos = background->center();
|
||||||
|
|
||||||
count = boost::lexical_cast<std::string>(creatureCount);
|
animation = new CCreaturePic(21, 48, creature);
|
||||||
|
|
||||||
printAtMiddle(c->namePl,149,30,FONT_SMALL,tytulowy,*bitmap); //creature name
|
std::string countStr = boost::lexical_cast<std::string>(count);
|
||||||
|
creatureCount = new CLabel(114, 174, FONT_TIMES, BOTTOMRIGHT, zwykly, countStr);
|
||||||
|
|
||||||
|
creatureName = new CLabel(149, 30, FONT_SMALL, CENTER, tytulowy, creature->namePl);
|
||||||
|
|
||||||
|
printLine(0, CGI->generaltexth->primarySkillNames[0], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
|
||||||
|
printLine(1, CGI->generaltexth->primarySkillNames[1], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
|
||||||
|
|
||||||
printLine(0, CGI->generaltexth->primarySkillNames[0], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
|
|
||||||
printLine(1, CGI->generaltexth->primarySkillNames[1], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
|
|
||||||
//if(c->shots)
|
|
||||||
// printLine(2, CGI->generaltexth->allTexts[198], c->shots);
|
|
||||||
if(stackNode->valOfBonuses(Bonus::SHOTS))
|
if(stackNode->valOfBonuses(Bonus::SHOTS))
|
||||||
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
|
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
|
||||||
|
|
||||||
@ -2176,67 +2178,35 @@ void CCreInfoWindow::init(const CCreature *cre, const CBonusSystemNode *stackNod
|
|||||||
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
||||||
dmgMultiply += heroOwner->Attack();
|
dmgMultiply += heroOwner->Attack();
|
||||||
|
|
||||||
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
|
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
|
||||||
printLine(4, CGI->generaltexth->allTexts[388], cre->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
|
printLine(4, CGI->generaltexth->allTexts[388], creature->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
|
||||||
printLine(6, CGI->generaltexth->zelp[441].first, cre->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
|
printLine(6, CGI->generaltexth->zelp[441].first, creature->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
|
||||||
|
|
||||||
//setting morale
|
//setting morale
|
||||||
morale = new MoraleLuckBox(true, genRect(42, 42, 24, 189));
|
morale = new MoraleLuckBox(true, genRect(42, 42, 22, 186));
|
||||||
morale->set(stackNode);
|
morale->set(stackNode);
|
||||||
//setting luck
|
//setting luck
|
||||||
luck = new MoraleLuckBox(false, genRect(42, 42, 77, 189));
|
luck = new MoraleLuckBox(false, genRect(42, 42, 75, 186));
|
||||||
luck->set(stackNode);
|
luck->set(stackNode);
|
||||||
|
|
||||||
//luck and morale
|
if(!LClicked)
|
||||||
int luck = 3, morale = 3;
|
abilityText = new CLabel(17, 231, FONT_SMALL, TOPLEFT, zwykly, creature->abilityText);
|
||||||
if(stackNode)
|
else
|
||||||
{
|
abilityText = NULL;
|
||||||
//add modifiers
|
|
||||||
luck += stackNode->LuckVal();
|
|
||||||
morale += stackNode->MoraleVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
blitAt(graphics->morale42->ourImages[morale].bitmap, 24, 189, *bitmap);
|
|
||||||
blitAt(graphics->luck42->ourImages[luck].bitmap, 77, 189, *bitmap);
|
|
||||||
|
|
||||||
|
|
||||||
if(!type)
|
|
||||||
{
|
|
||||||
printAtWB(c->abilityText,17,231,FONT_SMALL,35,zwykly,*bitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we are displying window fo r stack in battle, there are several more things that we need to display
|
//if we are displying window fo r stack in battle, there are several more things that we need to display
|
||||||
if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode))
|
if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode))
|
||||||
{
|
{
|
||||||
//spell effects
|
//print at most 3 spell effects
|
||||||
int printed=0; //how many effect pics have been printed
|
|
||||||
std::vector<si32> spells = battleStack->activeSpells();
|
std::vector<si32> spells = battleStack->activeSpells();
|
||||||
BOOST_FOREACH(si32 effect, spells)
|
for (size_t i=0; i< std::min(spells.size(), size_t(3)); i++)
|
||||||
{
|
effects.push_back(new CAnimImage("SpellInt", spells[i]+1, 0, 127 + 52*i, 186));
|
||||||
blitAt(graphics->spellEffectsPics->ourImages[effect + 1].bitmap, 127 + 52 * printed, 186, *bitmap);
|
|
||||||
++printed;
|
|
||||||
if(printed >= 3) //we can fit only 3 effects
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//print current health
|
//print current health
|
||||||
printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
|
printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CCreInfoWindow::~CCreInfoWindow()
|
|
||||||
{
|
|
||||||
for(int i=0; i<upgResCost.size();i++)
|
|
||||||
delete upgResCost[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreInfoWindow::activate()
|
|
||||||
{
|
|
||||||
CIntObject::activate();
|
|
||||||
if(!type)
|
|
||||||
activateRClick();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreInfoWindow::close()
|
void CCreInfoWindow::close()
|
||||||
{
|
{
|
||||||
GH.popIntTotally(this);
|
GH.popIntTotally(this);
|
||||||
@ -2244,26 +2214,8 @@ void CCreInfoWindow::close()
|
|||||||
|
|
||||||
void CCreInfoWindow::clickRight(tribool down, bool previousState)
|
void CCreInfoWindow::clickRight(tribool down, bool previousState)
|
||||||
{
|
{
|
||||||
if(down)
|
|
||||||
return;
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
void CCreInfoWindow::dismissF()
|
|
||||||
{
|
|
||||||
dsm();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreInfoWindow::keyPressed (const SDL_KeyboardEvent & key)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreInfoWindow::deactivate()
|
|
||||||
{
|
|
||||||
if(!type)
|
|
||||||
deactivateRClick();
|
|
||||||
CIntObject::deactivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLevelWindow::close()
|
void CLevelWindow::close()
|
||||||
{
|
{
|
||||||
|
@ -329,6 +329,7 @@ public:
|
|||||||
bool redrawParentOnScrolling;
|
bool redrawParentOnScrolling;
|
||||||
|
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
|
std::vector<CAnimImage* > effects;
|
||||||
CSlider *slider;
|
CSlider *slider;
|
||||||
|
|
||||||
//CTextBox( std::string Text, const Point &Pos, int w, int h, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly);
|
//CTextBox( std::string Text, const Point &Pos, int w, int h, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly);
|
||||||
@ -943,31 +944,30 @@ public:
|
|||||||
class CCreInfoWindow : public CIntObject
|
class CCreInfoWindow : public CIntObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//bool active; //TODO: comment me
|
CPicture *background;
|
||||||
int type;//0 - rclick popup; 1 - normal window
|
CLabel *creatureCount;
|
||||||
CPicture *bitmap; //background
|
CLabel *creatureName;
|
||||||
std::string count; //creature count in text format
|
CLabel *abilityText;
|
||||||
|
|
||||||
boost::function<void()> dsm; //dismiss button callback
|
CCreaturePic *animation;
|
||||||
CCreaturePic *anim; //related creature's animation
|
|
||||||
const CCreature *c; //related creature
|
|
||||||
std::vector<SComponent*> upgResCost; //cost of upgrade (if not possible then empty)
|
std::vector<SComponent*> upgResCost; //cost of upgrade (if not possible then empty)
|
||||||
|
std::vector<CAnimImage * > effects;
|
||||||
|
std::map<size_t, std::pair<CLabel*, CLabel* > > infoTexts;
|
||||||
|
|
||||||
MoraleLuckBox *luck, *morale;
|
MoraleLuckBox *luck, *morale;
|
||||||
|
|
||||||
AdventureMapButton *dismiss, *upgrade, *ok;
|
AdventureMapButton *dismiss, *upgrade, *ok;
|
||||||
CCreInfoWindow(const CStackInstance &st, int Type = 0, boost::function<void()> Upg = 0, boost::function<void()> Dsm = 0, UpgradeInfo *ui = NULL); //c-tor
|
|
||||||
CCreInfoWindow(const CStack &st, int Type = 0); //c-tor
|
CCreInfoWindow(const CStackInstance &st, bool LClicked, boost::function<void()> Upg = 0, boost::function<void()> Dsm = 0, UpgradeInfo *ui = NULL);
|
||||||
CCreInfoWindow(int Cid, int Type, int creatureCount); //c-tor
|
CCreInfoWindow(const CStack &st, bool LClicked = 0);
|
||||||
void init(const CCreature *cre, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int creatureCount);
|
CCreInfoWindow(int Cid, bool LClicked, int creatureCount);
|
||||||
|
~CCreInfoWindow();
|
||||||
|
|
||||||
|
void init(const CCreature *cre, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int creatureCount, bool LClicked);
|
||||||
void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false);
|
void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false);
|
||||||
~CCreInfoWindow(); //d-tor
|
|
||||||
void activate();
|
void clickRight(tribool down, bool previousState);
|
||||||
void close();
|
void close();
|
||||||
void clickRight(tribool down, bool previousState); //call-in
|
|
||||||
void dismissF();
|
|
||||||
void keyPressed (const SDL_KeyboardEvent & key); //call-in
|
|
||||||
void deactivate();
|
|
||||||
void show(SDL_Surface * to);
|
void show(SDL_Surface * to);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -975,7 +975,7 @@ public:
|
|||||||
class CArtPlace: public LRClickableAreaWTextComp
|
class CArtPlace: public LRClickableAreaWTextComp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int slotID; //0 head 1 shoulders 2 neck 3 right hand 4 left hand 5 torso 6 right ring 7 left ring 8 feet 9 misc. slot 1 10 misc. slot 2 11 misc. slot 3 12 misc. slot 4 13 ballista (war machine 1) 14 ammo cart (war machine 2) 15 first aid tent (war machine 3) 16 catapult 17 spell book 18 misc. slot 5 19+ backpack slots
|
int slotID; //Arts::EPOS enum + backpack starting from Arts::BACKPACK_START
|
||||||
|
|
||||||
bool picked;
|
bool picked;
|
||||||
bool marked;
|
bool marked;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2856,7 +2856,7 @@ void CPathfinder::calculatePaths(int3 src /*= int3(-1,-1,-1)*/, int movement /*=
|
|||||||
&& dp->accessible == CGPathNode::BLOCKVIS;
|
&& dp->accessible == CGPathNode::BLOCKVIS;
|
||||||
|
|
||||||
if (dp->accessible == CGPathNode::ACCESSIBLE
|
if (dp->accessible == CGPathNode::ACCESSIBLE
|
||||||
|| useEmbarkCost && allowEmbarkAndDisembark
|
|| (useEmbarkCost && allowEmbarkAndDisembark)
|
||||||
|| destTopVisObjID == SUBTERRANEAN_GATE_TYPE
|
|| destTopVisObjID == SUBTERRANEAN_GATE_TYPE
|
||||||
|| (guardedDst && !guardedSource)) // Can step into a hostile tile once.
|
|| (guardedDst && !guardedSource)) // Can step into a hostile tile once.
|
||||||
{
|
{
|
||||||
@ -2959,7 +2959,7 @@ bool CPathfinder::goodForLandSeaTransition()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero) : out(_out), CGameInfoCallback(_gs, -1), hero(_hero), FoW(getPlayerTeam(hero->tempOwner)->fogOfWarMap)
|
CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero) : CGameInfoCallback(_gs, -1), out(_out), hero(_hero), FoW(getPlayerTeam(hero->tempOwner)->fogOfWarMap)
|
||||||
{
|
{
|
||||||
useSubterraneanGates = true;
|
useSubterraneanGates = true;
|
||||||
allowEmbarkAndDisembark = true;
|
allowEmbarkAndDisembark = true;
|
||||||
|
355
lib/JsonNode.cpp
355
lib/JsonNode.cpp
@ -1,6 +1,9 @@
|
|||||||
#define VCMI_DLL
|
#define VCMI_DLL
|
||||||
#include "JsonNode.h"
|
#include "JsonNode.h"
|
||||||
|
|
||||||
|
#include <boost/assign.hpp>
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -18,6 +21,7 @@ JsonNode::JsonNode(const char *data, size_t datasize):
|
|||||||
type(DATA_NULL)
|
type(DATA_NULL)
|
||||||
{
|
{
|
||||||
JsonParser parser(data, datasize, *this);
|
JsonParser parser(data, datasize, *this);
|
||||||
|
JsonValidator validator(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode::JsonNode(std::string filename):
|
JsonNode::JsonNode(std::string filename):
|
||||||
@ -29,16 +33,27 @@ JsonNode::JsonNode(std::string filename):
|
|||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
char *input = new char[datasize];
|
char *input = new char[datasize];
|
||||||
fread((void*)input, 1, datasize, file);
|
datasize = fread((void*)input, 1, datasize, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
JsonParser parser(input, datasize, *this);
|
JsonParser parser(input, datasize, *this);
|
||||||
|
JsonValidator validator(*this);
|
||||||
delete [] input;
|
delete [] input;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode::JsonNode(const JsonNode ©):
|
JsonNode::JsonNode(const JsonNode ©):
|
||||||
type(DATA_NULL)
|
type(DATA_NULL)
|
||||||
{
|
{
|
||||||
*this = copy;
|
setType(copy.getType());
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
break; case DATA_NULL:
|
||||||
|
break; case DATA_BOOL: Bool() = copy.Bool();
|
||||||
|
break; case DATA_FLOAT: Float() = copy.Float();
|
||||||
|
break; case DATA_STRING: String() = copy.String();
|
||||||
|
break; case DATA_VECTOR: Vector() = copy.Vector();
|
||||||
|
break; case DATA_STRUCT: Struct() = copy.Struct();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode::~JsonNode()
|
JsonNode::~JsonNode()
|
||||||
@ -46,18 +61,16 @@ JsonNode::~JsonNode()
|
|||||||
setType(DATA_NULL);
|
setType(DATA_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode & JsonNode::operator =(const JsonNode &node)
|
void JsonNode::swap(JsonNode &b)
|
||||||
{
|
{
|
||||||
setType(node.getType());
|
using std::swap;
|
||||||
switch(type)
|
swap(data, b.data);
|
||||||
{
|
swap(type, b.type);
|
||||||
break; case DATA_NULL:
|
}
|
||||||
break; case DATA_BOOL: Bool() = node.Bool();
|
|
||||||
break; case DATA_FLOAT: Float() = node.Float();
|
JsonNode & JsonNode::operator =(JsonNode node)
|
||||||
break; case DATA_STRING: String() = node.String();
|
{
|
||||||
break; case DATA_VECTOR: Vector() = node.Vector();
|
swap(node);
|
||||||
break; case DATA_STRUCT: Struct() = node.Struct();
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,71 +204,100 @@ const JsonNode & JsonNode::operator[](std::string child) const
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//Helper to write content of map/vector
|
template<typename Iterator>
|
||||||
template<class iterator>
|
void JsonWriter::writeContainer(Iterator begin, Iterator end)
|
||||||
void writeContainer(const iterator &begin, const iterator &end, std::ostream &out, std::string prefix)
|
|
||||||
{
|
{
|
||||||
if (begin == end)
|
if (begin == end)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
iterator last = end;
|
prefix += '\t';
|
||||||
last--;
|
end--;
|
||||||
|
while (begin != end)
|
||||||
for (iterator it=begin; it != last; ++it)
|
|
||||||
{
|
{
|
||||||
writeNode(it, out, prefix);
|
writeEntry(begin++);
|
||||||
out<<",\n";
|
out<<",\n";
|
||||||
}
|
}
|
||||||
writeNode(last, out, prefix);
|
|
||||||
|
writeEntry(begin);
|
||||||
out<<"\n";
|
out<<"\n";
|
||||||
|
prefix.resize(prefix.size()-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeNode(JsonVector::const_iterator it, std::ostream &out, std::string prefix)
|
void JsonWriter::writeEntry(JsonMap::const_iterator entry)
|
||||||
{
|
{
|
||||||
out << prefix;
|
out << prefix;
|
||||||
it->write(out, prefix);
|
writeString(entry->first);
|
||||||
|
out << " : ";
|
||||||
|
writeNode(entry->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeNode(JsonMap::const_iterator it, std::ostream &out, std::string prefix)
|
void JsonWriter::writeEntry(JsonVector::const_iterator entry)
|
||||||
{
|
{
|
||||||
out << prefix << '\"' << it->first << '\"' << " : ";
|
out << prefix;
|
||||||
it->second.write(out, prefix);
|
writeNode(*entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonNode::write(std::ostream &out, std::string prefix) const
|
void JsonWriter::writeString(const std::string &string)
|
||||||
{
|
{
|
||||||
switch(type)
|
static const std::string escaped = "\"\\/\b\f\n\r\t";
|
||||||
|
|
||||||
|
out <<'\"';
|
||||||
|
size_t pos=0, start=0;
|
||||||
|
for (; pos<string.size(); pos++)
|
||||||
{
|
{
|
||||||
break; case DATA_NULL:
|
size_t escapedChar = escaped.find(string[pos]);
|
||||||
|
|
||||||
|
if (escapedChar != std::string::npos)
|
||||||
|
{
|
||||||
|
out.write(string.data()+start, pos - start);
|
||||||
|
out << '\\' << escaped[escapedChar];
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.write(string.data()+start, pos - start);
|
||||||
|
out <<'\"';
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonWriter::writeNode(const JsonNode &node)
|
||||||
|
{
|
||||||
|
switch(node.getType())
|
||||||
|
{
|
||||||
|
break; case JsonNode::DATA_NULL:
|
||||||
out << "null";
|
out << "null";
|
||||||
|
|
||||||
break; case DATA_BOOL:
|
break; case JsonNode::DATA_BOOL:
|
||||||
if (Bool())
|
if (node.Bool())
|
||||||
out << "true";
|
out << "true";
|
||||||
else
|
else
|
||||||
out << "false";
|
out << "false";
|
||||||
|
|
||||||
break; case DATA_FLOAT:
|
break; case JsonNode::DATA_FLOAT:
|
||||||
out << Float();
|
out << node.Float();
|
||||||
|
|
||||||
break; case DATA_STRING:
|
break; case JsonNode::DATA_STRING:
|
||||||
out << "\"" << String() << "\"";
|
writeString(node.String());
|
||||||
|
|
||||||
break; case DATA_VECTOR:
|
break; case JsonNode::DATA_VECTOR:
|
||||||
out << "[" << "\n";
|
out << "[" << "\n";
|
||||||
writeContainer(Vector().begin(), Vector().end(), out, prefix+'\t');
|
writeContainer(node.Vector().begin(), node.Vector().end());
|
||||||
out << prefix << "]";
|
out << prefix << "]";
|
||||||
|
|
||||||
break; case DATA_STRUCT:
|
break; case JsonNode::DATA_STRUCT:
|
||||||
out << "{" << "\n";
|
out << "{" << "\n";
|
||||||
writeContainer(Struct().begin(), Struct().end(), out, prefix+'\t');
|
writeContainer(node.Struct().begin(), node.Struct().end());
|
||||||
out << prefix << "}";
|
out << prefix << "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonWriter::JsonWriter(std::ostream &output, const JsonNode &node):
|
||||||
|
out(output)
|
||||||
|
{
|
||||||
|
writeNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream & operator<<(std::ostream &out, const JsonNode &node)
|
std::ostream & operator<<(std::ostream &out, const JsonNode &node)
|
||||||
{
|
{
|
||||||
node.write(out);
|
JsonWriter(out, node);
|
||||||
return out << "\n";
|
return out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +317,7 @@ JsonParser::JsonParser(const char * inputString, size_t stringSize, JsonNode &ro
|
|||||||
error("Not all file was parsed!", true);
|
error("Not all file was parsed!", true);
|
||||||
|
|
||||||
//TODO: better way to show errors (like printing file name as well)
|
//TODO: better way to show errors (like printing file name as well)
|
||||||
tlog2<<errors;
|
std::cout<<errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonParser::extractSeparator()
|
bool JsonParser::extractSeparator()
|
||||||
@ -335,7 +377,7 @@ bool JsonParser::extractWhitespace(bool verbose)
|
|||||||
if (input[pos] == '/')
|
if (input[pos] == '/')
|
||||||
pos++;
|
pos++;
|
||||||
else
|
else
|
||||||
error("Comments should have two slashes!", true);
|
error("Comments must consist from two slashes!", true);
|
||||||
|
|
||||||
while (pos < input.size() && input[pos] != '\n')
|
while (pos < input.size() && input[pos] != '\n')
|
||||||
pos++;
|
pos++;
|
||||||
@ -358,7 +400,7 @@ bool JsonParser::extractEscaping(std::string &str)
|
|||||||
break; case '\n': str += '\n';
|
break; case '\n': str += '\n';
|
||||||
break; case '\r': str += '\r';
|
break; case '\r': str += '\r';
|
||||||
break; case '\t': str += '\t';
|
break; case '\t': str += '\t';
|
||||||
break; default: return error("Uknown escape sequence!", true);
|
break; default: return error("Unknown escape sequence!", true);
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -442,7 +484,6 @@ bool JsonParser::extractTrue(JsonNode &node)
|
|||||||
if (!extractLiteral("true"))
|
if (!extractLiteral("true"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
node.setType(JsonNode::DATA_BOOL);
|
|
||||||
node.Bool() = true;
|
node.Bool() = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -452,7 +493,6 @@ bool JsonParser::extractFalse(JsonNode &node)
|
|||||||
if (!extractLiteral("false"))
|
if (!extractLiteral("false"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
node.setType(JsonNode::DATA_BOOL);
|
|
||||||
node.Bool() = false;
|
node.Bool() = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -484,33 +524,17 @@ bool JsonParser::extractStruct(JsonNode &node)
|
|||||||
if (node.Struct().find(key) != node.Struct().end())
|
if (node.Struct().find(key) != node.Struct().end())
|
||||||
error("Dublicated element encountered!", true);
|
error("Dublicated element encountered!", true);
|
||||||
|
|
||||||
JsonNode &child = node.Struct()[key];
|
|
||||||
|
|
||||||
if (!extractSeparator())
|
if (!extractSeparator())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!extractValue(child))
|
if (!extractElement(node.Struct()[key], '}'))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!extractWhitespace())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool comma = (input[pos] == ',');
|
|
||||||
if (comma )
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
if (!extractWhitespace())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input[pos] == '}')
|
if (input[pos] == '}')
|
||||||
{
|
{
|
||||||
pos++;
|
pos++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!comma)
|
|
||||||
error("Comma expected!", true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,33 +555,46 @@ bool JsonParser::extractArray(JsonNode &node)
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
//NOTE: currently 50% of time is this vector resizing.
|
||||||
|
//May be useful to use list during parsing and then swap() all items to vector
|
||||||
node.Vector().resize(node.Vector().size()+1);
|
node.Vector().resize(node.Vector().size()+1);
|
||||||
|
|
||||||
if (!extractValue(node.Vector().back()))
|
if (!extractElement(node.Vector().back(), ']'))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!extractWhitespace())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool comma = (input[pos] == ',');
|
|
||||||
if (comma )
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
if (!extractWhitespace())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input[pos] == ']')
|
if (input[pos] == ']')
|
||||||
{
|
{
|
||||||
pos++;
|
pos++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!comma)
|
|
||||||
error("Comma expected!", true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JsonParser::extractElement(JsonNode &node, char terminator)
|
||||||
|
{
|
||||||
|
if (!extractValue(node))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!extractWhitespace())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool comma = (input[pos] == ',');
|
||||||
|
if (comma )
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
if (!extractWhitespace())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input[pos] == terminator)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!comma)
|
||||||
|
error("Comma expected!", true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool JsonParser::extractFloat(JsonNode &node)
|
bool JsonParser::extractFloat(JsonNode &node)
|
||||||
{
|
{
|
||||||
assert(input[pos] == '-' || (input[pos] >= '0' && input[pos] <= '9'));
|
assert(input[pos] == '-' || (input[pos] >= '0' && input[pos] <= '9'));
|
||||||
@ -572,6 +609,7 @@ bool JsonParser::extractFloat(JsonNode &node)
|
|||||||
|
|
||||||
if (input[pos] < '0' || input[pos] > '9')
|
if (input[pos] < '0' || input[pos] > '9')
|
||||||
return error("Number expected!");
|
return error("Number expected!");
|
||||||
|
|
||||||
//Extract integer part
|
//Extract integer part
|
||||||
while (input[pos] >= '0' && input[pos] <= '9')
|
while (input[pos] >= '0' && input[pos] <= '9')
|
||||||
{
|
{
|
||||||
@ -614,3 +652,164 @@ bool JsonParser::error(const std::string &message, bool warning)
|
|||||||
|
|
||||||
return warning;
|
return warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const std::map<std::string, JsonNode::JsonType> stringToType =
|
||||||
|
boost::assign::map_list_of
|
||||||
|
("null", JsonNode::DATA_NULL) ("bool", JsonNode::DATA_BOOL)
|
||||||
|
("number", JsonNode::DATA_FLOAT) ("string", JsonNode::DATA_STRING)
|
||||||
|
("array", JsonNode::DATA_VECTOR) ("object", JsonNode::DATA_STRUCT);
|
||||||
|
|
||||||
|
//Check current schema entry for validness and converts "type" string to JsonType
|
||||||
|
bool JsonValidator::validateSchema(JsonNode::JsonType &type, const JsonNode &schema)
|
||||||
|
{
|
||||||
|
if (schema.isNull())
|
||||||
|
return addMessage("Missing schema for current entry!");
|
||||||
|
|
||||||
|
const JsonNode &nodeType = schema["type"];
|
||||||
|
if (nodeType.isNull())
|
||||||
|
return addMessage("Entry type is not defined in schema!");
|
||||||
|
|
||||||
|
if (nodeType.getType() != JsonNode::DATA_STRING)
|
||||||
|
return addMessage("Entry type must be string!");
|
||||||
|
|
||||||
|
std::map<std::string, JsonNode::JsonType>::const_iterator iter = stringToType.find(nodeType.String());
|
||||||
|
|
||||||
|
if (iter == stringToType.end())
|
||||||
|
return addMessage("Unknown entry type found!");
|
||||||
|
|
||||||
|
type = iter->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Replaces node with default value if needed and calls type-specific validators
|
||||||
|
bool JsonValidator::validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type)
|
||||||
|
{
|
||||||
|
if (node.isNull())
|
||||||
|
{
|
||||||
|
const JsonNode & defaultValue = schema["default"];
|
||||||
|
if (defaultValue.isNull())
|
||||||
|
return addMessage("Null entry without default entry!");
|
||||||
|
else
|
||||||
|
node = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != node.getType())
|
||||||
|
{
|
||||||
|
node.setType(JsonNode::DATA_NULL);
|
||||||
|
return addMessage("Type mismatch!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == JsonNode::DATA_VECTOR)
|
||||||
|
return validateItems(node, schema["items"]);
|
||||||
|
|
||||||
|
if (type == JsonNode::DATA_STRUCT)
|
||||||
|
return validateProperties(node, schema["properties"]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic checks common for any nodes
|
||||||
|
bool JsonValidator::validateNode(JsonNode &node, const JsonNode &schema, const std::string &name)
|
||||||
|
{
|
||||||
|
currentPath.push_back(name);
|
||||||
|
|
||||||
|
JsonNode::JsonType type = JsonNode::DATA_NULL;
|
||||||
|
if (!validateSchema(type, schema))
|
||||||
|
{
|
||||||
|
currentPath.pop_back();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateType(node, schema, type))
|
||||||
|
{
|
||||||
|
currentPath.pop_back();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPath.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Checks "items" entry from schema (type-specific check for Vector)
|
||||||
|
bool JsonValidator::validateItems(JsonNode &node, const JsonNode &schema)
|
||||||
|
{
|
||||||
|
JsonNode::JsonType type = JsonNode::DATA_NULL;
|
||||||
|
if (!validateSchema(type, schema))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BOOST_FOREACH(JsonNode &entry, node.Vector())
|
||||||
|
{
|
||||||
|
if (!validateType(entry, schema, type))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Checks "propertries" entry from schema (type-specific check for Struct)
|
||||||
|
//Function is similar to merging of two sorted lists - check every entry that present in one of the input nodes
|
||||||
|
bool JsonValidator::validateProperties(JsonNode &node, const JsonNode &schema)
|
||||||
|
{
|
||||||
|
if (schema.isNull())
|
||||||
|
return addMessage("Properties entry is missing for struct in schema");
|
||||||
|
|
||||||
|
JsonMap::iterator nodeIter = node.Struct().begin();
|
||||||
|
JsonMap::const_iterator schemaIter = schema.Struct().begin();
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
nodeIter++;
|
||||||
|
schemaIter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (nodeIter != node.Struct().end())
|
||||||
|
{
|
||||||
|
validateNode(nodeIter->second, JsonNode(), nodeIter->first);
|
||||||
|
nodeIter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (schemaIter != schema.Struct().end())
|
||||||
|
{
|
||||||
|
validateNode(node[schemaIter->first], schemaIter->second, schemaIter->first);
|
||||||
|
schemaIter++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JsonValidator::addMessage(const std::string &message)
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
|
||||||
|
stream << "At ";
|
||||||
|
BOOST_FOREACH(const std::string &path, currentPath)
|
||||||
|
stream << path<<"/";
|
||||||
|
stream << "\t Error: " << message <<"\n";
|
||||||
|
errors += stream.str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonValidator::JsonValidator(JsonNode &root)
|
||||||
|
{
|
||||||
|
const JsonNode schema = root["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
|
||||||
|
//else
|
||||||
|
// addMessage("Schema not found!", true);
|
||||||
|
|
||||||
|
//TODO: better way to show errors (like printing file name as well)
|
||||||
|
std::cout<<errors;
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "../global.h"
|
#include "../global.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -49,8 +50,8 @@ public:
|
|||||||
|
|
||||||
~JsonNode();
|
~JsonNode();
|
||||||
|
|
||||||
// Deep copy of this node
|
void swap(JsonNode &b);
|
||||||
JsonNode& operator =(const JsonNode &node);
|
JsonNode& operator =(JsonNode node);
|
||||||
|
|
||||||
//Convert node to another type. Converting to NULL will clear all data
|
//Convert node to another type. Converting to NULL will clear all data
|
||||||
void setType(JsonType Type);
|
void setType(JsonType Type);
|
||||||
@ -72,9 +73,6 @@ public:
|
|||||||
const JsonVector & Vector() const;
|
const JsonVector & Vector() const;
|
||||||
const JsonMap & Struct() const;
|
const JsonMap & Struct() const;
|
||||||
|
|
||||||
//formatted output of this node in JSON format
|
|
||||||
void write(std::ostream &out, std::string prefix="") const;
|
|
||||||
|
|
||||||
//operator [], for structs only - get child node by name
|
//operator [], for structs only - get child node by name
|
||||||
JsonNode & operator[](std::string child);
|
JsonNode & operator[](std::string child);
|
||||||
const JsonNode & operator[](std::string child) const;
|
const JsonNode & operator[](std::string child) const;
|
||||||
@ -83,9 +81,25 @@ public:
|
|||||||
static const JsonNode nullNode;
|
static const JsonNode nullNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class JsonWriter
|
||||||
|
{
|
||||||
|
//prefix for each line (tabulation)
|
||||||
|
std::string prefix;
|
||||||
|
std::ostream &out;
|
||||||
|
public:
|
||||||
|
template<typename Iterator>
|
||||||
|
void writeContainer(Iterator begin, Iterator end);
|
||||||
|
void writeEntry(JsonMap::const_iterator entry);
|
||||||
|
void writeEntry(JsonVector::const_iterator entry);
|
||||||
|
void writeString(const std::string &string);
|
||||||
|
void writeNode(const JsonNode &node);
|
||||||
|
JsonWriter(std::ostream &output, const JsonNode &node);
|
||||||
|
};
|
||||||
|
|
||||||
std::ostream & operator<<(std::ostream &out, const JsonNode &node);
|
std::ostream & operator<<(std::ostream &out, const JsonNode &node);
|
||||||
|
|
||||||
//Tiny string class that use const char* as data for speed, members are private for ease of debugging
|
//Tiny string class that uses const char* as data for speed, members are private
|
||||||
|
//for ease of debugging and some compatibility with std::string
|
||||||
class constString
|
class constString
|
||||||
{
|
{
|
||||||
const char *data;
|
const char *data;
|
||||||
@ -110,10 +124,9 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Internal class for std::string -> JsonNode conversion
|
//Internal class for string -> JsonNode conversion
|
||||||
class JsonParser
|
class JsonParser
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string errors; // Contains description of all encountered errors
|
std::string errors; // Contains description of all encountered errors
|
||||||
constString input; // Input data
|
constString input; // Input data
|
||||||
unsigned int lineCount; // Currently parsed line, starting from 1
|
unsigned int lineCount; // Currently parsed line, starting from 1
|
||||||
@ -126,6 +139,7 @@ class JsonParser
|
|||||||
bool extractString(std::string &string);
|
bool extractString(std::string &string);
|
||||||
bool extractWhitespace(bool verbose = true);
|
bool extractWhitespace(bool verbose = true);
|
||||||
bool extractSeparator();
|
bool extractSeparator();
|
||||||
|
bool extractElement(JsonNode &node, char terminator);
|
||||||
|
|
||||||
//Methods for extracting JSON data
|
//Methods for extracting JSON data
|
||||||
bool extractArray(JsonNode &node);
|
bool extractArray(JsonNode &node);
|
||||||
@ -143,3 +157,24 @@ class JsonParser
|
|||||||
public:
|
public:
|
||||||
JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
|
JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:
|
||||||
|
// - "schema" entry from root node is used for validation and will be removed
|
||||||
|
// - any missing entries will be replaced with default value from schema (if present)
|
||||||
|
// - if entry uses different type than defined in schema it will be removed
|
||||||
|
// - entries nod described in schema will be kept unchanged
|
||||||
|
class JsonValidator
|
||||||
|
{
|
||||||
|
std::string errors; // Contains description of all encountered errors
|
||||||
|
std::list<std::string> currentPath; // path from root node to current one
|
||||||
|
|
||||||
|
bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type);
|
||||||
|
bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema);
|
||||||
|
bool validateNode(JsonNode &node, const JsonNode &schema, const std::string &name);
|
||||||
|
bool validateItems(JsonNode &node, const JsonNode &schema);
|
||||||
|
bool validateProperties(JsonNode &node, const JsonNode &schema);
|
||||||
|
|
||||||
|
bool addMessage(const std::string &message);
|
||||||
|
public:
|
||||||
|
JsonValidator(JsonNode &root);
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user