1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

- handling of incorrect or missing configuration files (settings.json\defaultSettings.json)

- better code for recruitment window, fixes #1013
- minor tweak to adv.map classes
This commit is contained in:
Ivan Savenko 2012-06-22 11:40:16 +00:00
parent 933049ee91
commit 770a6e077c
10 changed files with 328 additions and 183 deletions

View File

@ -247,7 +247,7 @@ void CHeroList::update(const CGHeroInstance * hero)
for (auto iter = list->getItems().begin(); iter != list->getItems().end(); iter++)
{
auto item = dynamic_cast<CHeroItem*>(*iter);
if (item && item->hero == hero)
if (item && item->hero == hero && vstd::contains(LOCPLINT->wanderingHeroes, hero))
{
item->update();
return;
@ -817,13 +817,13 @@ void CInfoBar::showSelection()
auto hero = dynamic_cast<const CGHeroInstance *>(adventureInt->selection);
if (hero)
{
showHeroSelection(hero, false);
showHeroSelection(hero);
return;
}
auto town = dynamic_cast<const CGTownInstance *>(adventureInt->selection);
if (town)
{
showTownSelection(town, false);
showTownSelection(town);
return;
}
}
@ -903,7 +903,7 @@ void CInfoBar::updateEnemyTurn(double progress)
redraw();
}
void CInfoBar::showHeroSelection(const CGHeroInstance * hero, bool onlyUpdate)
void CInfoBar::showHeroSelection(const CGHeroInstance * hero)
{
if (!hero)
return;
@ -914,7 +914,7 @@ void CInfoBar::showHeroSelection(const CGHeroInstance * hero, bool onlyUpdate)
redraw();
}
void CInfoBar::showTownSelection(const CGTownInstance * town, bool onlyUpdate)
void CInfoBar::showTownSelection(const CGTownInstance * town)
{
if (!town)
return;

View File

@ -277,8 +277,6 @@ class CInfoBar : public CIntObject
//removes all information about current state, deactivates timer (if any)
void reset(EState newState);
//reset to default view - selected object
void showSelection();
void tick();
@ -301,10 +299,12 @@ public:
/// NOTE: currently DISABLED. Check comments in CInfoBar::CVisibleInfo::loadEnemyTurn()
void updateEnemyTurn(double progress);
/// reset to default view - selected object
void showSelection();
/// show hero\town information
/// if onlyUpdate set to true this call won't switch to town\hero but only update current view
void showHeroSelection(const CGHeroInstance * hero, bool onlyUpdate);
void showTownSelection(const CGTownInstance * town, bool onlyUpdate);
void showHeroSelection(const CGHeroInstance * hero);
void showTownSelection(const CGTownInstance * town);
/// for 3 seconds shows amount of town halls and players status
void showGameStatus();

View File

@ -981,7 +981,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
assert(sel);
LOCPLINT->cb->setSelection(sel);
selection = sel;
if (LOCPLINT->battleInt == NULL)
if (LOCPLINT->battleInt == NULL && active & GENERAL)
CCS->musich->playMusic(CCS->musich->terrainMusics[LOCPLINT->cb->getTile(sel->visitablePos())->tertype], -1);
if(centerView)
centerOn(sel);
@ -991,7 +991,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
{
auto town = dynamic_cast<const CGTownInstance*>(sel);
infoBar.showTownSelection(town, false);
infoBar.showTownSelection(town);
townList.select(town);
heroList.select(nullptr);
@ -1002,7 +1002,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
{
auto hero = dynamic_cast<const CGHeroInstance*>(sel);
infoBar.showHeroSelection(hero, false);
infoBar.showHeroSelection(hero);
heroList.select(hero);
townList.select(nullptr);

View File

@ -198,7 +198,6 @@ class CCastleInterface : public CWindowObject, public CWindowWithGarrison
CGStatusBar * statusbar;
CTownInfo *hall, *fort;
CTownList * townlist;
CAdventureMapButton *exit;
CAdventureMapButton *split;
@ -206,6 +205,8 @@ class CCastleInterface : public CWindowObject, public CWindowWithGarrison
std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
public:
CTownList * townlist;
//TODO: remove - currently used only in dialog messages
CDefEssential* bicons; //150x70 buildings imgs
@ -214,6 +215,7 @@ public:
HeroSlots *heroes;
CCastleBuildings *builds;
//from - previously selected castle (if any)
CCastleInterface(const CGTownInstance * Town, const CGTownInstance * from = nullptr); //c-tor
~CCastleInterface();

View File

@ -251,6 +251,17 @@ int main(int argc, char** argv)
const JsonNode& video = settings["video"];
const JsonNode& res = video["screenRes"];
//something is really wrong...
if (res["width"].Float() < 100 || res["height"].Float() < 100)
{
tlog0 << "Fatal error: failed to load settings!\n";
tlog0 << "Possible reasons:\n";
tlog0 << "\tCorrupted local configuration file at " << GVCMIDirs.UserPath << "/config/settings.json\n";
tlog0 << "\tMissing or corrupted global configuration file at " << GameConstants::DATA_DIR << "/config/defaultSettings.json\n";
tlog0 << "VCMI will now exit...\n";
exit(EXIT_FAILURE);
}
setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool());
tlog0 <<"\tInitializing screen: "<<pomtime.getDiff() << std::endl;

View File

@ -367,12 +367,36 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
const CArmedInstance *newSelection = nullptr;
if (makingTurn)
{
//find new object for selection: either hero
int next = adventureInt->getNextHeroIndex(vstd::find_pos(wanderingHeroes, hero));
if (next >= 0)
newSelection = wanderingHeroes[next];
//or town
if (!newSelection || newSelection == hero)
{
if (towns.empty())
newSelection = nullptr;
else
newSelection = towns.front();
}
}
wanderingHeroes -= hero;
if(vstd::contains(paths, hero))
paths.erase(hero);
adventureInt->heroList.update(hero);
if (makingTurn)
adventureInt->select(newSelection, true);
else
adventureInt->selection = nullptr;
}
void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -560,6 +584,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID,
break;
}
adventureInt->townList.update(town);
castleInt->townlist->update(town);
}
void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
@ -1076,8 +1101,8 @@ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
else if(GH.listInt.size() && (town->ID == 17 || town->ID == 20 || town->ID == 106)) //external dwelling
{
CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.topInt());
if(crw)
crw->initCres();
if(crw && crw->dwelling == town)
crw->availableCreaturesChanged();
}
}
@ -2159,10 +2184,7 @@ void CPlayerInterface::tryDiggging(const CGHeroInstance *h)
void CPlayerInterface::updateInfo(const CGObjectInstance * specific)
{
if (specific->ID == GameConstants::TOWNI_TYPE)
adventureInt->infoBar.showTownSelection(dynamic_cast<const CGTownInstance *>(specific), true);
else
adventureInt->infoBar.showHeroSelection(dynamic_cast<const CGHeroInstance *>(specific), true);
adventureInt->infoBar.showSelection();
}
void CPlayerInterface::battleNewRoundFirst( int round )

View File

@ -1039,15 +1039,146 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool An
anim = new CCreatureAnim(0, 0, cre->animDefName, Rect());
anim->clipRect(cre->doubleWide?170:150, 155, bg->pos.w, bg->pos.h);
anim->startPreview();
pos.w = bg->pos.w;
pos.h = bg->pos.h;
}
void CRecruitmentWindow::Max()
CRecruitmentWindow::CCreatureCard::CCreatureCard(CRecruitmentWindow *window, const CCreature *crea, int totalAmount):
CIntObject(LCLICK | RCLICK),
parent(window),
selected(false),
creature(crea),
amount(totalAmount)
{
slider->moveToMax();
OBJ_CONSTRUCTION_CAPTURING_ALL;
pic = new CCreaturePic(1,1, creature, true, true);
// 1 + 1 px for borders
pos.w = pic->pos.w + 2;
pos.h = pic->pos.h + 2;
}
void CRecruitmentWindow::Buy()
void CRecruitmentWindow::CCreatureCard::select(bool on)
{
int crid = creatures[which].ID,
selected = on;
redraw();
}
void CRecruitmentWindow::CCreatureCard::clickLeft(tribool down, bool previousState)
{
if (down)
parent->select(this);
}
void CRecruitmentWindow::CCreatureCard::clickRight(tribool down, bool previousState)
{
if (down)
GH.pushInt(createCreWindow(creature->idNumber, 0, 0));
}
void CRecruitmentWindow::CCreatureCard::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
if (selected)
drawBorder(to, pos, int3(248, 0, 0));
else
drawBorder(to, pos, int3(232, 212, 120));
}
CRecruitmentWindow::CCostBox::CCostBox(Rect position, std::string title)
{
type |= REDRAW_PARENT;
pos = position + pos;
OBJ_CONSTRUCTION_CAPTURING_ALL;
new CLabel(pos.w/2, 10, FONT_SMALL, CENTER, Colors::Cornsilk, title);
}
void CRecruitmentWindow::CCostBox::set(TResources res)
{
//just update values
BOOST_FOREACH(auto & item, resources)
{
item.second.first->setTxt(boost::lexical_cast<std::string>(res[item.first]));
}
}
void CRecruitmentWindow::CCostBox::createItems(TResources res)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
BOOST_FOREACH(auto & curr, resources)
{
delete curr.second.first;
delete curr.second.second;
}
resources.clear();
TResources::nziterator iter(res);
while (iter.valid())
{
CAnimImage * image = new CAnimImage("RESOURCE", iter->resType);
CLabel * text = new CLabel(15, 43, FONT_SMALL, CENTER, Colors::Cornsilk, "0");
resources.insert(std::make_pair(iter->resType, std::make_pair(text, image)));
iter++;
}
if (!resources.empty())
{
int curx = pos.w / 2 - (16 * resources.size()) - (8 * (resources.size() - 1));
//reverse to display gold as first resource
BOOST_REVERSE_FOREACH(auto & res, resources)
{
res.second.first->moveBy(Point(curx, 22));
res.second.second->moveBy(Point(curx, 22));
curx += 48;
}
}
redraw();
}
void CRecruitmentWindow::select(CCreatureCard *card)
{
if (card == selected)
return;
if (selected)
selected->select(false);
selected = card;
if (selected)
selected->select(true);
if (card)
{
si32 maxAmount = card->creature->maxAmount(LOCPLINT->cb->getResourceAmount());
vstd::amin(maxAmount, card->amount);
slider->setAmount(maxAmount);
if(slider->value)
slider->moveTo(0);
else // if slider already at 0 - emulate call to sliderMoved()
sliderMoved(0);
costPerTroopValue->createItems(card->creature->cost);
totalCostValue->createItems(card->creature->cost);
costPerTroopValue->set(card->creature->cost);
//Recruit %s
title->setTxt(boost::str(boost::format(CGI->generaltexth->tcommands[21]) % card->creature->namePl));
maxButton->block(maxAmount == 0);
slider->block(maxAmount == 0);
}
}
void CRecruitmentWindow::buy()
{
int crid = selected->creature->idNumber,
dstslot = dst-> getSlotFor(crid);
if(dstslot < 0 && !vstd::contains(CGI->arth->bigArtifacts,CGI->arth->convertMachineID(crid, true))) //no available slot
@ -1067,175 +1198,122 @@ void CRecruitmentWindow::Buy()
return;
}
recruit(crid, slider->value);
onRecruit(crid, slider->value);
if(level >= 0)
close();
else
slider->moveTo(0);
}
void CRecruitmentWindow::Cancel()
{
close();
}
void CRecruitmentWindow::sliderMoved(int to)
{
buy->block(!to);
redraw();
}
void CRecruitmentWindow::clickLeft(tribool down, bool previousState)
{
for(int i=0;i<creatures.size();i++)
{
Rect creaPos = Rect(creatures[i].pos) + pos;
if(isItIn(&creaPos, GH.current->motion.x, GH.current->motion.y))
{
which = i;
int newAmount = std::min(amounts[i],creatures[i].amount);
slider->setAmount(newAmount);
max->block(!newAmount);
if(slider->value > newAmount)
slider->moveTo(newAmount);
else
slider->moveTo(slider->value);
redraw();
break;
}
}
}
void CRecruitmentWindow::clickRight(tribool down, bool previousState)
{
if(down)
{
int curx = 192 + 51 - (CREATURE_WIDTH*creatures.size()/2) - (SPACE_BETWEEN*(creatures.size()-1)/2);
for(int i=0;i<creatures.size();i++)
{
const int sCREATURE_WIDTH = CREATURE_WIDTH; // gcc -O0 workaround
Rect creatureRect = genRect(132, sCREATURE_WIDTH, pos.x+curx, pos.y+64);
if(isItIn(&creatureRect, GH.current->motion.x, GH.current->motion.y))
{
CIntObject *popup = createCreWindow(creatures[i].ID, 0, 0);
GH.pushInt(popup);
break;
}
curx += TOTAL_CREATURE_WIDTH;
}
}
}
void CRecruitmentWindow::showAll(SDL_Surface * to)
{
CWindowObject::showAll(to);
// recruit\total values
drawBorder(to, pos.x + 172, pos.y + 222, 67, 42, int3(239,215,123));
drawBorder(to, pos.x + 246, pos.y + 222, 67, 42, int3(239,215,123));
//cost boxes
drawBorder(to, pos.x + 64, pos.y + 222, 99, 76, int3(239,215,123));
drawBorder(to, pos.x + 322, pos.y + 222, 99, 76, int3(239,215,123));
//buttons borders
drawBorder(to, pos.x + 133, pos.y + 312, 66, 34, int3(173,142,66));
drawBorder(to, pos.x + 211, pos.y + 312, 66, 34, int3(173,142,66));
drawBorder(to, pos.x + 289, pos.y + 312, 66, 34, int3(173,142,66));
char pom[15];
SDL_itoa(creatures[which].amount-slider->value,pom,10); //available
printAtMiddleLoc(pom,205,253,FONT_SMALL,Colors::Cornsilk,to);
SDL_itoa(slider->value,pom,10); //recruit
printAtMiddleLoc(pom,279,253,FONT_SMALL,Colors::Cornsilk,to);
printAtMiddleLoc(CGI->generaltexth->allTexts[16] + " " + CGI->creh->creatures[creatures[which].ID]->namePl,243,32,FONT_BIG,Colors::Jasmine,to); //eg "Recruit Dragon flies"
int curx = 122-creatures[which].res.size()*24;
for(int i=creatures[which].res.size()-1; i>=0; i--)// decrement used to make gold displayed as first res
{
blitAtLoc(graphics->resources32->ourImages[creatures[which].res[i].first].bitmap,curx,243,to);
blitAtLoc(graphics->resources32->ourImages[creatures[which].res[i].first].bitmap,curx+258,243,to);
SDL_itoa(creatures[which].res[i].second,pom,10);
printAtMiddleLoc(pom,curx+15,287,FONT_SMALL,Colors::Cornsilk,to);
SDL_itoa(creatures[which].res[i].second * slider->value,pom,10);
printAtMiddleLoc(pom,curx+15+258,287,FONT_SMALL,Colors::Cornsilk,to);
curx+=32+16;//size of bitmap + distance between them
}
for(int j=0;j<creatures.size();j++)
{
if(which==j)
drawBorderLoc(to,creatures[j].pos,int3(255,0,0));
else
drawBorderLoc(to,creatures[j].pos,int3(239,215,123));
}
}
CRecruitmentWindow::CRecruitmentWindow(const CGDwelling *Dwelling, int Level, const CArmedInstance *Dst, const boost::function<void(int,int)> &Recruit, int y_offset):
CWindowObject(PLAYER_COLORED, "TPRCRT"),
recruit(Recruit),
dwelling(Dwelling),
onRecruit(Recruit),
level(Level),
dst(Dst)
dst(Dst),
selected(nullptr),
dwelling(Dwelling)
{
addUsedEvents(LCLICK | RCLICK);
OBJ_CONSTRUCTION_CAPTURING_ALL;
moveBy(Point(0, y_offset));
OBJ_CONSTRUCTION_CAPTURING_ALL;
new CGStatusBar(new CPicture(*background, Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
which = 0;
bar = new CGStatusBar(new CPicture(*background, Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
max = new CAdventureMapButton(CGI->generaltexth->zelp[553],boost::bind(&CRecruitmentWindow::Max,this),134,313,"IRCBTNS.DEF",SDLK_m);
buy = new CAdventureMapButton(CGI->generaltexth->zelp[554],boost::bind(&CRecruitmentWindow::Buy,this),212,313,"IBY6432.DEF",SDLK_RETURN);
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[555],boost::bind(&CRecruitmentWindow::Cancel,this),290,313,"ICN6432.DEF",SDLK_ESCAPE);
slider = new CSlider(176,279,135,0,0,0,0,true);
slider->moved = boost::bind(&CRecruitmentWindow::sliderMoved,this, _1);
initCres();
maxButton = new CAdventureMapButton(CGI->generaltexth->zelp[553],boost::bind(&CSlider::moveToMax,slider),134,313,"IRCBTNS.DEF",SDLK_m);
buyButton = new CAdventureMapButton(CGI->generaltexth->zelp[554],boost::bind(&CRecruitmentWindow::buy,this),212,313,"IBY6432.DEF",SDLK_RETURN);
cancelButton = new CAdventureMapButton(CGI->generaltexth->zelp[555],boost::bind(&CRecruitmentWindow::close,this),290,313,"ICN6432.DEF",SDLK_ESCAPE);
title = new CLabel(243, 32, FONT_BIG, CENTER, Colors::Jasmine);
availableValue = new CLabel(205, 253, FONT_SMALL, CENTER, Colors::Cornsilk);
toRecruitValue = new CLabel(279, 253, FONT_SMALL, CENTER, Colors::Cornsilk);
costPerTroopValue = new CCostBox(Rect(65, 222, 97, 74), CGI->generaltexth->allTexts[346]);
totalCostValue = new CCostBox(Rect(323, 222, 97, 74), CGI->generaltexth->allTexts[466]);
new CLabel(113, 232, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[346]); //cost per troop t
new CLabel(205, 233, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[465]); //available t
new CLabel(279, 233, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[16]); //recruit t
new CLabel(371, 232, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[466]); //total cost t
//border for creatures
int curx = 192 + 50 - (CREATURE_WIDTH*creatures.size()/2) - (SPACE_BETWEEN*(creatures.size()-1)/2);
for(int i=0;i<creatures.size();i++)
{
creatures[i].pos.x = curx-1;
creatures[i].pos.y = 65 - 1;
creatures[i].pos.w = 100 + 2;
creatures[i].pos.h = 130 + 2;
creatures[i].pic = new CCreaturePic(curx, 65, CGI->creh->creatures[creatures[i].ID]);
curx += TOTAL_CREATURE_WIDTH;
}
if(!creatures[0].amount || !amounts[0])
{
max->block(true);
slider->block(true);
}
buy->block(true);
availableCreaturesChanged();
}
void CRecruitmentWindow::initCres()
void CRecruitmentWindow::availableCreaturesChanged()
{
creatures.clear();
amounts.clear();
OBJ_CONSTRUCTION_CAPTURING_ALL;
//deselect card
select(nullptr);
static const int SPACE_BETWEEN = 18;
static const int CREATURE_WIDTH = 102;
static const int TOTAL_CREATURE_WIDTH = SPACE_BETWEEN + CREATURE_WIDTH;
//delete old cards
BOOST_FOREACH(auto & card, cards)
delete card;
cards.clear();
for(int i=0; i<dwelling->creatures.size(); i++)
{
//find appropriate level
if(level >= 0 && i != level)
continue;
for(int j = dwelling->creatures[i].second.size() - 1; j >= 0 ; j--)
{
creatures.resize(creatures.size()+1);
creinfo &cur = creatures.back();
int amount = dwelling->creatures[i].first;
cur.amount = dwelling->creatures[i].first;
cur.ID = dwelling->creatures[i].second[j];
const CCreature * cre= CGI->creh->creatures[cur.ID];
for(int k=0; k<cre->cost.size(); k++)
if(cre->cost[k])
cur.res.push_back(std::make_pair(k,cre->cost[k]));
amounts.push_back(cre->maxAmount(LOCPLINT->cb->getResourceAmount()));
}
//create new cards
BOOST_REVERSE_FOREACH(auto & creature, dwelling->creatures[i].second)
cards.push_back(new CCreatureCard(this, CGI->creh->creatures[creature], amount));
}
slider->setAmount(std::min(amounts[which],creatures[which].amount));
assert(!cards.empty());
//now we know total amount of cards and can move them to correct position
int curx = 192 + 50 - (CREATURE_WIDTH*cards.size()/2) - (SPACE_BETWEEN*(cards.size()-1)/2);
BOOST_FOREACH(auto & card, cards)
{
card->moveBy(Point(curx, 64));
curx += TOTAL_CREATURE_WIDTH;
}
select(cards.front());
if(slider->value)
slider->moveTo(0);
else // if slider already at 0 - emulate call to sliderMoved()
sliderMoved(0);
}
void CRecruitmentWindow::sliderMoved(int to)
{
if (!selected)
return;
buyButton->block(!to);
availableValue->setTxt(boost::lexical_cast<std::string>(selected->amount - to));
toRecruitValue->setTxt(boost::lexical_cast<std::string>(to));
totalCostValue->set(selected->creature->cost * to);
}
CSplitWindow::CSplitWindow(const CCreature * creature, boost::function<void(int, int)> callback_,
@ -2202,6 +2280,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan
case EMarketMode::RESOURCE_PLAYER:
case EMarketMode::RESOURCE_ARTIFACT:
new CLabel(154, 148, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[270]);
break;
case EMarketMode::CREATURE_RESOURCE:
//%s's Creatures
@ -3138,6 +3217,9 @@ void CSystemOptionsWindow::setGameRes(int index)
while (index--)
iter++;
//do not set resolution to illegal one (0x0)
assert(iter!=conf.guiOptions.end() && iter->first.first > 0 && iter->first.second > 0);
Settings gameRes = settings.write["video"]["screenRes"];
gameRes["width"].Float() = iter->first.first;
gameRes["height"].Float() = iter->first.second;

View File

@ -333,39 +333,62 @@ public:
/// Recruitment window where you can recruit creatures
class CRecruitmentWindow : public CWindowObject
{
public:
static const int SPACE_BETWEEN = 18;
static const int CREATURE_WIDTH = 102;
static const int TOTAL_CREATURE_WIDTH = SPACE_BETWEEN + CREATURE_WIDTH;
struct creinfo
class CCreatureCard : public CIntObject
{
SDL_Rect pos;
CRecruitmentWindow * parent;
CCreaturePic *pic; //creature's animation
int ID, amount; //creature ID and available amount
std::vector<std::pair<int,int> > res; //res_id - cost_per_unit
};
std::vector<int> amounts; //how many creatures we can afford
std::vector<creinfo> creatures; //recruitable creatures
boost::function<void(int,int)> recruit; //void (int ID, int amount) <-- call to recruit creatures
CSlider *slider; //for selecting amount
CAdventureMapButton *max, *buy, *cancel;
CGStatusBar *bar;
int which; //which creature is active
bool selected;
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void showAll(SDL_Surface *to);
public:
const CCreature * creature;
si32 amount;
void select(bool on);
CCreatureCard(CRecruitmentWindow * window, const CCreature *crea, int totalAmount);
};
/// small class to display creature costs
class CCostBox : public CIntObject
{
std::map<int, std::pair<CLabel *, CAnimImage * > > resources;
public:
//res - resources to show
void set(TResources res);
//res - visible resources
CCostBox(Rect position, std::string title);
void createItems(TResources res);
};
boost::function<void(int,int)> onRecruit; //void (int ID, int amount) <-- call to recruit creatures
const CGDwelling *dwelling;
int level;
const CArmedInstance *dst;
void Max();
void Buy();
void Cancel();
CCreatureCard * selected;
std::vector<CCreatureCard *> cards;
CSlider *slider; //for selecting amount
CAdventureMapButton *maxButton, *buyButton, *cancelButton;
//labels for visible values
CLabel * title;
CLabel * availableValue;
CLabel * toRecruitValue;
CCostBox * costPerTroopValue;
CCostBox * totalCostValue;
void select(CCreatureCard * card);
void buy();
void sliderMoved(int to);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void showAll(SDL_Surface * to);
void initCres();
void showAll(SDL_Surface *to);
public:
const CGDwelling * const dwelling;
CRecruitmentWindow(const CGDwelling *Dwelling, int Level, const CArmedInstance *Dst, const boost::function<void(int,int)> & Recruit, int y_offset = 0); //creatures - pairs<creature_ID,amount> //c-tor
void availableCreaturesChanged();
};
/// Split window where creatures can be splitted up into two single unit stacks

View File

@ -751,17 +751,22 @@ CSlider::CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int
if(style == 0)
{
std::string name = horizontal?"IGPCRDIV.DEF":"OVBUTN2.DEF";
CAnimation *animLeft = new CAnimation(name);
//NOTE: this images do not have "blocked" frames. They should be implemented somehow (e.g. palette transform or something...)
//use source def to create custom animations. Format "name.def:123" will load this frame from def file
CAnimation *animLeft = new CAnimation();
animLeft->setCustom(name + ":0", 0);
animLeft->setCustom(name + ":1", 1);
left->setImage(animLeft);
left->setOffset(0);
CAnimation *animRight = new CAnimation(name);
CAnimation *animRight = new CAnimation();
animRight->setCustom(name + ":2", 0);
animRight->setCustom(name + ":3", 1);
right->setImage(animRight);
right->setOffset(2);
CAnimation *animSlider = new CAnimation(name);
CAnimation *animSlider = new CAnimation();
animSlider->setCustom(name + ":4", 0);
slider->setImage(animSlider);
slider->setOffset(4);
}
else
{
@ -1512,7 +1517,7 @@ bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
void CTextInput::filenameFilter(std::string & text, const std::string &)
{
static const std::string forbiddenChars = "<>:\"/\\|?*"; //if we are entering a filename, some special characters won't be allowed
static const std::string forbiddenChars = "<>:\"/\\|?*\r\n"; //if we are entering a filename, some special characters won't be allowed
size_t pos;
while ((pos = text.find_first_of(forbiddenChars)) != std::string::npos)
text.erase(pos, 1);

View File

@ -995,7 +995,7 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
}
else if(ID == 6) //shipyard
{
const TerrainTile *tile = getTile(t->bestLocation());
const TerrainTile *tile = getTile(t->bestLocation(), false);
if(!tile || tile->tertype != TerrainTile::water )
ret = EBuildingState::NO_WATER; //lack of water