mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-15 01:24:45 +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:
@ -247,7 +247,7 @@ void CHeroList::update(const CGHeroInstance * hero)
|
|||||||
for (auto iter = list->getItems().begin(); iter != list->getItems().end(); iter++)
|
for (auto iter = list->getItems().begin(); iter != list->getItems().end(); iter++)
|
||||||
{
|
{
|
||||||
auto item = dynamic_cast<CHeroItem*>(*iter);
|
auto item = dynamic_cast<CHeroItem*>(*iter);
|
||||||
if (item && item->hero == hero)
|
if (item && item->hero == hero && vstd::contains(LOCPLINT->wanderingHeroes, hero))
|
||||||
{
|
{
|
||||||
item->update();
|
item->update();
|
||||||
return;
|
return;
|
||||||
@ -817,13 +817,13 @@ void CInfoBar::showSelection()
|
|||||||
auto hero = dynamic_cast<const CGHeroInstance *>(adventureInt->selection);
|
auto hero = dynamic_cast<const CGHeroInstance *>(adventureInt->selection);
|
||||||
if (hero)
|
if (hero)
|
||||||
{
|
{
|
||||||
showHeroSelection(hero, false);
|
showHeroSelection(hero);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto town = dynamic_cast<const CGTownInstance *>(adventureInt->selection);
|
auto town = dynamic_cast<const CGTownInstance *>(adventureInt->selection);
|
||||||
if (town)
|
if (town)
|
||||||
{
|
{
|
||||||
showTownSelection(town, false);
|
showTownSelection(town);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -903,7 +903,7 @@ void CInfoBar::updateEnemyTurn(double progress)
|
|||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInfoBar::showHeroSelection(const CGHeroInstance * hero, bool onlyUpdate)
|
void CInfoBar::showHeroSelection(const CGHeroInstance * hero)
|
||||||
{
|
{
|
||||||
if (!hero)
|
if (!hero)
|
||||||
return;
|
return;
|
||||||
@ -914,7 +914,7 @@ void CInfoBar::showHeroSelection(const CGHeroInstance * hero, bool onlyUpdate)
|
|||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInfoBar::showTownSelection(const CGTownInstance * town, bool onlyUpdate)
|
void CInfoBar::showTownSelection(const CGTownInstance * town)
|
||||||
{
|
{
|
||||||
if (!town)
|
if (!town)
|
||||||
return;
|
return;
|
||||||
|
@ -277,8 +277,6 @@ class CInfoBar : public CIntObject
|
|||||||
|
|
||||||
//removes all information about current state, deactivates timer (if any)
|
//removes all information about current state, deactivates timer (if any)
|
||||||
void reset(EState newState);
|
void reset(EState newState);
|
||||||
//reset to default view - selected object
|
|
||||||
void showSelection();
|
|
||||||
|
|
||||||
void tick();
|
void tick();
|
||||||
|
|
||||||
@ -301,10 +299,12 @@ public:
|
|||||||
/// NOTE: currently DISABLED. Check comments in CInfoBar::CVisibleInfo::loadEnemyTurn()
|
/// NOTE: currently DISABLED. Check comments in CInfoBar::CVisibleInfo::loadEnemyTurn()
|
||||||
void updateEnemyTurn(double progress);
|
void updateEnemyTurn(double progress);
|
||||||
|
|
||||||
|
/// reset to default view - selected object
|
||||||
|
void showSelection();
|
||||||
|
|
||||||
/// show hero\town information
|
/// 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);
|
||||||
void showHeroSelection(const CGHeroInstance * hero, bool onlyUpdate);
|
void showTownSelection(const CGTownInstance * town);
|
||||||
void showTownSelection(const CGTownInstance * town, bool onlyUpdate);
|
|
||||||
|
|
||||||
/// for 3 seconds shows amount of town halls and players status
|
/// for 3 seconds shows amount of town halls and players status
|
||||||
void showGameStatus();
|
void showGameStatus();
|
||||||
|
@ -981,7 +981,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
|
|||||||
assert(sel);
|
assert(sel);
|
||||||
LOCPLINT->cb->setSelection(sel);
|
LOCPLINT->cb->setSelection(sel);
|
||||||
selection = 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);
|
CCS->musich->playMusic(CCS->musich->terrainMusics[LOCPLINT->cb->getTile(sel->visitablePos())->tertype], -1);
|
||||||
if(centerView)
|
if(centerView)
|
||||||
centerOn(sel);
|
centerOn(sel);
|
||||||
@ -991,7 +991,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
|
|||||||
{
|
{
|
||||||
auto town = dynamic_cast<const CGTownInstance*>(sel);
|
auto town = dynamic_cast<const CGTownInstance*>(sel);
|
||||||
|
|
||||||
infoBar.showTownSelection(town, false);
|
infoBar.showTownSelection(town);
|
||||||
townList.select(town);
|
townList.select(town);
|
||||||
heroList.select(nullptr);
|
heroList.select(nullptr);
|
||||||
|
|
||||||
@ -1002,7 +1002,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
|
|||||||
{
|
{
|
||||||
auto hero = dynamic_cast<const CGHeroInstance*>(sel);
|
auto hero = dynamic_cast<const CGHeroInstance*>(sel);
|
||||||
|
|
||||||
infoBar.showHeroSelection(hero, false);
|
infoBar.showHeroSelection(hero);
|
||||||
heroList.select(hero);
|
heroList.select(hero);
|
||||||
townList.select(nullptr);
|
townList.select(nullptr);
|
||||||
|
|
||||||
|
@ -198,7 +198,6 @@ class CCastleInterface : public CWindowObject, public CWindowWithGarrison
|
|||||||
CGStatusBar * statusbar;
|
CGStatusBar * statusbar;
|
||||||
|
|
||||||
CTownInfo *hall, *fort;
|
CTownInfo *hall, *fort;
|
||||||
CTownList * townlist;
|
|
||||||
|
|
||||||
CAdventureMapButton *exit;
|
CAdventureMapButton *exit;
|
||||||
CAdventureMapButton *split;
|
CAdventureMapButton *split;
|
||||||
@ -206,6 +205,8 @@ class CCastleInterface : public CWindowObject, public CWindowWithGarrison
|
|||||||
std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
|
std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
CTownList * townlist;
|
||||||
|
|
||||||
//TODO: remove - currently used only in dialog messages
|
//TODO: remove - currently used only in dialog messages
|
||||||
CDefEssential* bicons; //150x70 buildings imgs
|
CDefEssential* bicons; //150x70 buildings imgs
|
||||||
|
|
||||||
@ -214,6 +215,7 @@ public:
|
|||||||
HeroSlots *heroes;
|
HeroSlots *heroes;
|
||||||
CCastleBuildings *builds;
|
CCastleBuildings *builds;
|
||||||
|
|
||||||
|
//from - previously selected castle (if any)
|
||||||
CCastleInterface(const CGTownInstance * Town, const CGTownInstance * from = nullptr); //c-tor
|
CCastleInterface(const CGTownInstance * Town, const CGTownInstance * from = nullptr); //c-tor
|
||||||
~CCastleInterface();
|
~CCastleInterface();
|
||||||
|
|
||||||
|
@ -251,6 +251,17 @@ int main(int argc, char** argv)
|
|||||||
const JsonNode& video = settings["video"];
|
const JsonNode& video = settings["video"];
|
||||||
const JsonNode& res = video["screenRes"];
|
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());
|
setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool());
|
||||||
|
|
||||||
tlog0 <<"\tInitializing screen: "<<pomtime.getDiff() << std::endl;
|
tlog0 <<"\tInitializing screen: "<<pomtime.getDiff() << std::endl;
|
||||||
|
@ -367,12 +367,36 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
|||||||
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
|
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
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;
|
wanderingHeroes -= hero;
|
||||||
if(vstd::contains(paths, hero))
|
if(vstd::contains(paths, hero))
|
||||||
paths.erase(hero);
|
paths.erase(hero);
|
||||||
|
|
||||||
adventureInt->heroList.update(hero);
|
adventureInt->heroList.update(hero);
|
||||||
|
if (makingTurn)
|
||||||
|
adventureInt->select(newSelection, true);
|
||||||
|
else
|
||||||
|
adventureInt->selection = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
|
void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
@ -560,6 +584,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
adventureInt->townList.update(town);
|
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)
|
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
|
else if(GH.listInt.size() && (town->ID == 17 || town->ID == 20 || town->ID == 106)) //external dwelling
|
||||||
{
|
{
|
||||||
CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.topInt());
|
CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.topInt());
|
||||||
if(crw)
|
if(crw && crw->dwelling == town)
|
||||||
crw->initCres();
|
crw->availableCreaturesChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2159,10 +2184,7 @@ void CPlayerInterface::tryDiggging(const CGHeroInstance *h)
|
|||||||
|
|
||||||
void CPlayerInterface::updateInfo(const CGObjectInstance * specific)
|
void CPlayerInterface::updateInfo(const CGObjectInstance * specific)
|
||||||
{
|
{
|
||||||
if (specific->ID == GameConstants::TOWNI_TYPE)
|
adventureInt->infoBar.showSelection();
|
||||||
adventureInt->infoBar.showTownSelection(dynamic_cast<const CGTownInstance *>(specific), true);
|
|
||||||
else
|
|
||||||
adventureInt->infoBar.showHeroSelection(dynamic_cast<const CGHeroInstance *>(specific), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::battleNewRoundFirst( int round )
|
void CPlayerInterface::battleNewRoundFirst( int round )
|
||||||
|
@ -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 = new CCreatureAnim(0, 0, cre->animDefName, Rect());
|
||||||
anim->clipRect(cre->doubleWide?170:150, 155, bg->pos.w, bg->pos.h);
|
anim->clipRect(cre->doubleWide?170:150, 155, bg->pos.w, bg->pos.h);
|
||||||
anim->startPreview();
|
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);
|
dstslot = dst-> getSlotFor(crid);
|
||||||
|
|
||||||
if(dstslot < 0 && !vstd::contains(CGI->arth->bigArtifacts,CGI->arth->convertMachineID(crid, true))) //no available slot
|
if(dstslot < 0 && !vstd::contains(CGI->arth->bigArtifacts,CGI->arth->convertMachineID(crid, true))) //no available slot
|
||||||
@ -1067,175 +1198,122 @@ void CRecruitmentWindow::Buy()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
recruit(crid, slider->value);
|
onRecruit(crid, slider->value);
|
||||||
if(level >= 0)
|
if(level >= 0)
|
||||||
close();
|
close();
|
||||||
else
|
else
|
||||||
slider->moveTo(0);
|
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)
|
void CRecruitmentWindow::showAll(SDL_Surface * to)
|
||||||
{
|
{
|
||||||
CWindowObject::showAll(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 + 172, pos.y + 222, 67, 42, int3(239,215,123));
|
||||||
drawBorder(to, pos.x + 246, 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 + 64, pos.y + 222, 99, 76, int3(239,215,123));
|
||||||
drawBorder(to, pos.x + 322, 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 + 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 + 211, pos.y + 312, 66, 34, int3(173,142,66));
|
||||||
drawBorder(to, pos.x + 289, 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):
|
CRecruitmentWindow::CRecruitmentWindow(const CGDwelling *Dwelling, int Level, const CArmedInstance *Dst, const boost::function<void(int,int)> &Recruit, int y_offset):
|
||||||
CWindowObject(PLAYER_COLORED, "TPRCRT"),
|
CWindowObject(PLAYER_COLORED, "TPRCRT"),
|
||||||
recruit(Recruit),
|
onRecruit(Recruit),
|
||||||
dwelling(Dwelling),
|
|
||||||
level(Level),
|
level(Level),
|
||||||
dst(Dst)
|
dst(Dst),
|
||||||
|
selected(nullptr),
|
||||||
|
dwelling(Dwelling)
|
||||||
{
|
{
|
||||||
addUsedEvents(LCLICK | RCLICK);
|
moveBy(Point(0, y_offset));
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
|
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 = new CSlider(176,279,135,0,0,0,0,true);
|
||||||
slider->moved = boost::bind(&CRecruitmentWindow::sliderMoved,this, _1);
|
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(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(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
|
availableCreaturesChanged();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRecruitmentWindow::initCres()
|
void CRecruitmentWindow::availableCreaturesChanged()
|
||||||
{
|
{
|
||||||
creatures.clear();
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
amounts.clear();
|
|
||||||
|
//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++)
|
for(int i=0; i<dwelling->creatures.size(); i++)
|
||||||
{
|
{
|
||||||
|
//find appropriate level
|
||||||
if(level >= 0 && i != level)
|
if(level >= 0 && i != level)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(int j = dwelling->creatures[i].second.size() - 1; j >= 0 ; j--)
|
int amount = dwelling->creatures[i].first;
|
||||||
{
|
|
||||||
creatures.resize(creatures.size()+1);
|
|
||||||
creinfo &cur = creatures.back();
|
|
||||||
|
|
||||||
cur.amount = dwelling->creatures[i].first;
|
//create new cards
|
||||||
cur.ID = dwelling->creatures[i].second[j];
|
BOOST_REVERSE_FOREACH(auto & creature, dwelling->creatures[i].second)
|
||||||
const CCreature * cre= CGI->creh->creatures[cur.ID];
|
cards.push_back(new CCreatureCard(this, CGI->creh->creatures[creature], amount));
|
||||||
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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_,
|
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_PLAYER:
|
||||||
case EMarketMode::RESOURCE_ARTIFACT:
|
case EMarketMode::RESOURCE_ARTIFACT:
|
||||||
new CLabel(154, 148, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[270]);
|
new CLabel(154, 148, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[270]);
|
||||||
|
break;
|
||||||
|
|
||||||
case EMarketMode::CREATURE_RESOURCE:
|
case EMarketMode::CREATURE_RESOURCE:
|
||||||
//%s's Creatures
|
//%s's Creatures
|
||||||
@ -3138,6 +3217,9 @@ void CSystemOptionsWindow::setGameRes(int index)
|
|||||||
while (index--)
|
while (index--)
|
||||||
iter++;
|
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"];
|
Settings gameRes = settings.write["video"]["screenRes"];
|
||||||
gameRes["width"].Float() = iter->first.first;
|
gameRes["width"].Float() = iter->first.first;
|
||||||
gameRes["height"].Float() = iter->first.second;
|
gameRes["height"].Float() = iter->first.second;
|
||||||
|
@ -333,39 +333,62 @@ public:
|
|||||||
/// Recruitment window where you can recruit creatures
|
/// Recruitment window where you can recruit creatures
|
||||||
class CRecruitmentWindow : public CWindowObject
|
class CRecruitmentWindow : public CWindowObject
|
||||||
{
|
{
|
||||||
public:
|
class CCreatureCard : public CIntObject
|
||||||
static const int SPACE_BETWEEN = 18;
|
|
||||||
static const int CREATURE_WIDTH = 102;
|
|
||||||
static const int TOTAL_CREATURE_WIDTH = SPACE_BETWEEN + CREATURE_WIDTH;
|
|
||||||
|
|
||||||
struct creinfo
|
|
||||||
{
|
{
|
||||||
SDL_Rect pos;
|
CRecruitmentWindow * parent;
|
||||||
CCreaturePic *pic; //creature's animation
|
CCreaturePic *pic; //creature's animation
|
||||||
int ID, amount; //creature ID and available amount
|
bool selected;
|
||||||
std::vector<std::pair<int,int> > res; //res_id - cost_per_unit
|
|
||||||
};
|
void clickLeft(tribool down, bool previousState);
|
||||||
std::vector<int> amounts; //how many creatures we can afford
|
void clickRight(tribool down, bool previousState);
|
||||||
std::vector<creinfo> creatures; //recruitable creatures
|
void showAll(SDL_Surface *to);
|
||||||
boost::function<void(int,int)> recruit; //void (int ID, int amount) <-- call to recruit creatures
|
public:
|
||||||
CSlider *slider; //for selecting amount
|
const CCreature * creature;
|
||||||
CAdventureMapButton *max, *buy, *cancel;
|
si32 amount;
|
||||||
CGStatusBar *bar;
|
|
||||||
int which; //which creature is active
|
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;
|
int level;
|
||||||
const CArmedInstance *dst;
|
const CArmedInstance *dst;
|
||||||
|
|
||||||
void Max();
|
CCreatureCard * selected;
|
||||||
void Buy();
|
std::vector<CCreatureCard *> cards;
|
||||||
void Cancel();
|
|
||||||
|
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 sliderMoved(int to);
|
||||||
void clickLeft(tribool down, bool previousState);
|
|
||||||
void clickRight(tribool down, bool previousState);
|
void showAll(SDL_Surface *to);
|
||||||
void showAll(SDL_Surface * to);
|
public:
|
||||||
void initCres();
|
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
|
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
|
/// Split window where creatures can be splitted up into two single unit stacks
|
||||||
|
@ -751,17 +751,22 @@ CSlider::CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int
|
|||||||
if(style == 0)
|
if(style == 0)
|
||||||
{
|
{
|
||||||
std::string name = horizontal?"IGPCRDIV.DEF":"OVBUTN2.DEF";
|
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->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->setImage(animRight);
|
||||||
right->setOffset(2);
|
|
||||||
|
|
||||||
CAnimation *animSlider = new CAnimation(name);
|
CAnimation *animSlider = new CAnimation();
|
||||||
|
animSlider->setCustom(name + ":4", 0);
|
||||||
slider->setImage(animSlider);
|
slider->setImage(animSlider);
|
||||||
slider->setOffset(4);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1512,7 +1517,7 @@ bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
|
|||||||
|
|
||||||
void CTextInput::filenameFilter(std::string & text, const std::string &)
|
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;
|
size_t pos;
|
||||||
while ((pos = text.find_first_of(forbiddenChars)) != std::string::npos)
|
while ((pos = text.find_first_of(forbiddenChars)) != std::string::npos)
|
||||||
text.erase(pos, 1);
|
text.erase(pos, 1);
|
||||||
|
@ -995,7 +995,7 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
|
|||||||
}
|
}
|
||||||
else if(ID == 6) //shipyard
|
else if(ID == 6) //shipyard
|
||||||
{
|
{
|
||||||
const TerrainTile *tile = getTile(t->bestLocation());
|
const TerrainTile *tile = getTile(t->bestLocation(), false);
|
||||||
|
|
||||||
if(!tile || tile->tertype != TerrainTile::water )
|
if(!tile || tile->tertype != TerrainTile::water )
|
||||||
ret = EBuildingState::NO_WATER; //lack of water
|
ret = EBuildingState::NO_WATER; //lack of water
|
||||||
|
Reference in New Issue
Block a user