ResearchView::ResearchView(ViewManager* gvm) : View(gvm), book(new BookView(4)) { buttons.resize(BUTTON_COUNT); buttons[PREV_PAGE] = Button::buildSimple("Prev page", 15, 9, LSI(SCROLL, 7)); buttons[NEXT_PAGE] = Button::buildSimple("Next page", 289, 9, LSI(SCROLL, 8)); buttons[PREV_PAGE]->setAction([this]() { book->prevPage(); buttons[NEXT_PAGE]->show(); buttons[PREV_PAGE]->showIf(book->hasPrevPage()); }); buttons[NEXT_PAGE]->setAction([this]() { book->nextPage(); buttons[PREV_PAGE]->show(); buttons[NEXT_PAGE]->showIf(book->hasNextPage()); }); u16 sx = 22, sy = 24; u16 dy = 37, dx = 148; u16 ww = 123, hh = 36; for (u16 i = 0; i < 8; ++i) areas.push_back((new Clickable(sx + (i/4)*dx, sy + (i%4)*dy, ww, hh))->setAction([this,i](){ indexClicked(i); })); auto backToMap = [gvm](){ gvm->switchView(VIEW_MAIN); }; areas.push_back((new Clickable(0,10, 5, 189))->setAction(backToMap)); areas.push_back((new Clickable(315,10, 5, 189))->setAction(backToMap)); areas.push_back((new Clickable(6,180, 308, 19))->setAction(backToMap)); }
/* !DO NOT ALTER FUNCTION SIGNATURE! */ int callback_ofc_capable_switch_ofc_logical_switches_ofc_switch_ofc_controllers_ofc_controller (void ** data, XMLDIFF_OP op, xmlNodePtr node, struct nc_err** error) { nc_verb_verbose("%s: data=%p, op=%d\n", __PRETTY_FUNCTION__, data, op); print_element_names(node, 0); if (NULL == *data) { *data = calloc(1, sizeof(struct lsi)); assert(*data); } if ((XMLDIFF_ADD) & op) { if (NULL == LSI(data)->controller_list_add) { LSI(data)->controller_list_add = list_new(); assert(LSI(data)->controller_list_add); } list_append_data(LSI(data)->controller_list_add, __data); __data = NULL; } else if ((XMLDIFF_REM) & op) { if (NULL == LSI(data)->controller_list_del) { LSI(data)->controller_list_del = list_new(); assert(LSI(data)->controller_list_del); } list_append_data(LSI(data)->controller_list_del, __data); __data = NULL; } else { nc_verb_error("not implemented"); assert(0); } return EXIT_SUCCESS; }
void AlchemyView::draw() { const u16 bar_length = 49; //printf("Percent: %f\n", percent); // draw backdrop Gfx::drawClipped(LSI(MAGIC, 52), 77, 66, 0, 0, 166, 67); // if conversion is inverted power -> gold switch label if (inverted) Gfx::draw(LSI(MAGIC, 59), 89, 76); // draw bar on amount bar int shift = Gfx::fticks % 8; int length = (s32)(percent*(49))+4; // TODO: should be animated / needs fix if (length > shift) { Gfx::drawClipped(LSI(MAGIC, 57), 133 + shift, 91, 0, 0, length - shift, 7); Gfx::drawClipped(LSI(MAGIC, 57), 133, 91, length - shift, 0, shift, 7); } // draw symbol on amount bar Gfx::draw(LSI(MAGIC, 58), 133+(s32)(percent*(bar_length)), 91); int flx = 95, frx = 197, fy = 90; int gamount = 0, mamount = 0; // TODO: manage ALCHEMIST trait for wizards if (!inverted) { gamount = amount; mamount = amount/2; } else { gamount = amount/2; mamount = amount; } // TODO: font is not exactly the same, and space is removed otherwise it would go over the box Fonts::drawString(fmt::format("{}GP", gamount), FontFaces::Small::YELLOW, flx, fy, ALIGN_LEFT); Fonts::drawString(fmt::format("{}MP", mamount), FontFaces::Small::YELLOW, frx, fy, ALIGN_LEFT); }
void NewGameView::draw() { Gfx::draw(LSI(NEWGAME, 0), 0, 0); /*Gfx::drawGrayScale(GfxData::unitGfxSpec(UnitSpec::summonSpec(UnitID::GREAT_DRAKE)).still, 30, 30); Gfx::drawGlow(GfxData::unitGfxSpec(UnitSpec::summonSpec(UnitID::GREAT_DRAKE)).still, 30, 30, CHAOS);*/ switch (phase) { case GAME_OPTIONS: { Gfx::draw(LSI(NEWGAME, 1), 165, 0); } } }
void ArmyView::activate() { if (!propPalette) { const Palette* basePalette = LSI(UNITVIEW, 28).palette(); // TODO: color at index 82 must become transparent propPalette = std::unique_ptr<const Palette>(new DerivedPalette(basePalette, 255, 1, Color(0,0,0,0))); } }
AlchemyView::AlchemyView(ViewManager* gvm) : View(gvm), inverted(false), percent(0.0f), amount(0) { buttons.resize(BUTTON_COUNT); buttons[CANCEL] = Button::buildBistate("Cancel", 95, 105, LSI(MAGIC, 53))->setAction([gvm](){ gvm->closeOverview(); }); buttons[OK] = Button::buildBistate("Ok", 178, 105, LSI(MAGIC, 54))-> setAction([this,gvm](){ g->alchemy(player, amount, !inverted); gvm->closeOverview(); }); auto invertAction = [this](){ buttons[SWITCH]->showIf(inverted); buttons[SWITCH2]->showIf(!inverted); amount = static_cast<s32>(percent * (inverted ? player->totalGoldPool() : player->totalManaPool())); inverted = !inverted; }; buttons[SWITCH] = Button::buildBistate("Switch1", 148, 105, LSI(MAGIC, 55))->setAction(invertAction); buttons[SWITCH2] = Button::buildBistate("Switch2", 148, 105, LSI(MAGIC, 56))->setAction(invertAction)->hide(); }
NewGameView::NewGameView(ViewManager * gvm) : View(gvm) { buttons.resize(BUTTON_COUNT); buttons[OPTIONS_OK] = Button::buildBistate("Ok", 252, 179, LSI(NEWGAME, 2)); buttons[OPTIONS_CANCEL] = Button::buildBistate("Cancel", 171, 179, LSI(NEWGAME, 3)); const auto* face = FontFaces::MediumBold::BROWN_START; buttons[OPTIONS_DIFFICULTY] = Button::buildOffsetted("Difficulty", 251, 39, LSI(NEWGAME,4)); buttons[OPTIONS_OPPONENTS] = Button::buildOffsetted("Opponents", 251, 66, LSI(NEWGAME,5)); buttons[OPTIONS_LAND_SIZE] = Button::buildOffsetted("Land Size", 251, 93, LSI(NEWGAME,6)); buttons[OPTIONS_MAGIC] = Button::buildOffsetted("Magic", 251, 120, LSI(NEWGAME,7)); buttons[OPTIONS_DIFFICULTY]->setTextInfo(TextInfo("", face)); buttons[OPTIONS_OPPONENTS]->setTextInfo(TextInfo("", face)); buttons[OPTIONS_LAND_SIZE]->setTextInfo(TextInfo("", face)); buttons[OPTIONS_MAGIC]->setTextInfo(TextInfo("", face)); buttons[OPTIONS_DIFFICULTY]->setAction([&](){ settings.group(SETTING_DIFFICULTY).next(); updateLabelsOptions(); }); buttons[OPTIONS_OPPONENTS]->setAction([&](){ settings.group(SETTING_OPPONENTS).next(); updateLabelsOptions(); }); buttons[OPTIONS_LAND_SIZE]->setAction([&](){ settings.group(SETTING_LAND_SIZE).next(); updateLabelsOptions(); }); buttons[OPTIONS_MAGIC]->setAction([&](){ settings.group(SETTING_MAGIC_POWER).next(); updateLabelsOptions(); }); updateLabelsOptions(); }
SpellBookView::SpellBookView(ViewManager* gvm) : View(gvm), book(new BookView(6)), combatMode(false) { buttons.resize(BUTTON_COUNT); buttons[PREV_PAGE] = Button::buildSimple("Prev page", 29, 15, LSI(SPELLS, 1)); buttons[NEXT_PAGE] = Button::buildSimple("Next page", 274, 15, LSI(SPELLS, 2)); buttons[PREV_PAGE]->setAction([this]() { book->prevPage(); buttons[NEXT_PAGE]->show(); buttons[PREV_PAGE]->showIf(book->hasPrevPage()); }); buttons[NEXT_PAGE]->setAction([this]() { book->nextPage(); buttons[PREV_PAGE]->show(); buttons[NEXT_PAGE]->showIf(book->hasNextPage()); }); addArea((new Clickable(175,165,18,29))->setAction([gvm](){ gvm->closeOverview(); })); ClickableGrid* spellGrid = new ClickableGrid(topLeftX[0]-2, topLeftY[0]-2, 125, 22, 6, 2, 7, 0); spellGrid->setCellAction([this](coord_t x, coord_t y, MouseButton bt) { if (bt == MouseButton::BUTTON_LEFT) startCast(book->getEntry(x*6 + y)); else return true; return true; }); addArea(spellGrid); /* for (u16 k = 0; k < 2; ++k) for (u16 i = 0; i < 6;++i) addArea((new Clickable(topLeftX[k]-2,topLeftY[k]+22*i-2,125,22))->setAction([k,i,this](coord_t, coord_t, MouseButton bt){ startCast(book->getEntry(k*6 + i)); }));*/ }
/* !DO NOT ALTER FUNCTION SIGNATURE! */ int callback_ofc_capable_switch_ofc_logical_switches_ofc_switch_ofc_datapath_id (void ** data, XMLDIFF_OP op, xmlNodePtr node, struct nc_err** error) { nc_verb_verbose("%s: data=%p, op=%d\n", __PRETTY_FUNCTION__, data, op); assert(NULL == __data); if (NULL == *data) { *data = calloc(1, sizeof(struct lsi)); assert(*data); } if ((XMLDIFF_ADD|XMLDIFF_REM) & op) { xmlChar* text = xmlNodeListGetString(node->doc, node->children, 1); uint64_t dpid = parse_dpid(text); xmlFree(text); LSI(data)->dpid = dpid; } else { // todo add operation to modify dpid nc_verb_error("not implemented"); assert(0); } return EXIT_SUCCESS; }
CityView::CityView(ViewManager* gvm) : View(gvm) { cityEnchantPage = 0; buttons.resize(BUTTON_COUNT); buttons[BUY] = Button::buildTristate("Buy", 214, 188, LSI(BACKGRND, 7), LSI(BACKGRND, 14)); buttons[CHANGE] = Button::buildBistate("Change", 247, 188, LSI(BACKGRND, 8)); buttons[OK] = Button::buildBistate("Ok", 286, 188, LSI(BACKGRND, 9)); /* TODO: add behavior */ buttons[PREV_CITY_ENCHANT] = Button::buildBistate("Prev City Enchant", 201, 50, LSI(BACKGRND,15))->setAction([this](){ const size_t pageCount = Math::roundWithMod(city->getSpells().size(), CITY_ENCHANT_PER_PAGE); cityEnchantPage = Math::negativeWrap(cityEnchantPage, pageCount); }); buttons[NEXT_CITY_ENCHANT] = Button::buildBistate("Prev City Enchant", 201, 85, LSI(BACKGRND,16))->setAction([this](){ const size_t pageCount = Math::roundWithMod(city->getSpells().size(), CITY_ENCHANT_PER_PAGE); cityEnchantPage = (cityEnchantPage + 1) % pageCount; }); buttons[BUY]->deactivate(); buttons[BUY]->setAction([this](){ player->send(new msgs::Confirm(fmt::sprintf("Do you wish to spend %d Gold by purchasing a %s?", city->getProductable()->productionCost(), city->getProductable()->productionName()), [&]() { g->cityMechanics.buyProduction(city); })); }); buttons[OK]->setAction([gvm](){ gvm->switchView(VIEW_MAIN); }); buttons[CHANGE]->setAction([gvm,this]{ gvm->productionView()->setCity(city); gvm->switchOverview(VIEW_PRODUCTION); }); addArea(new ClickableGrid(139, 50, 60, 7, 6, 1))->setCellAction([this](coord_t x, coord_t y) { clickOnCitySpell(y); }); }
void SpellBookView::drawPage(u16 index) { const BookView::Page* page = book->current(index); if (!page || page->actualSize() == 0) return; Fonts::drawString(i18n::s(page->getTitle()), FontFaces::Serif::BROWN, topLeftX[index]+60, topLeftY[index]-16, ALIGN_CENTER); for (int i = 0; i < 6; ++i) { const ResearchStatus& entry = page->at(i); if (entry.spell) { const Spell* spell = entry.spell; int curY = topLeftY[index]+ROW_HEIGHT*i; u16 clip, clip2; if (spell != player->book()->getCurrentCast()) { clip = Fonts::drawString(i18n::s(spell->name), FontFaces::Small::BROWN, topLeftX[index]-1, curY-1, ALIGN_LEFT); clip2 = Fonts::drawString(fmt::sprintf("%d MP", g->spellMechanics.actualManaCost(player, spell, combatMode)), FontFaces::Small::BROWN, topLeftX[index]+ROW_WIDTH+7, curY-1, ALIGN_RIGHT); } else { clip = Fonts::drawString(i18n::s(spell->name), FontFaces::Small::BLINK_WHITE_GREY, topLeftX[index]-1, curY-1, ALIGN_LEFT); clip2 = Fonts::drawString(fmt::sprintf("%d MP", g->spellMechanics.actualManaCost(player, spell, combatMode)), FontFaces::Small::BLINK_WHITE_GREY, topLeftX[index]+ROW_WIDTH+7, curY-1, ALIGN_RIGHT); } Gfx::drawClipped(LSI(SPELLS,10), topLeftX[index]+clip+3, curY, clip+3, ROW_HEIGHT*i, -3-clip2, 6); s16 turns; bool instant = false; if (!combatMode) { // if we're not in combat mode mana symbols are used to show how many turns are needed for the cast if (player->getAvailableMana() > 0) { turns = g->spellMechanics.actualManaCost(player, spell, combatMode) / player->getAvailableMana(); instant = turns == 0 ? true : false; if (turns == 0) turns = 1; } else turns = 40; } else { // in combat mode symbols are used to show how many casts of the spell are allowed according to cast skill // TODO: real calculation of spell skill turns = 100 / g->spellMechanics.actualManaCost(player, spell, combatMode); } SpriteInfo schoolIcon = GfxData::schoolGfxSpec(spell->school).symbol; // draw mana symbols on spell entry if (!instant) { s16 toDo = std::min((int)turns, 20); for (int j = 0; j < toDo; ++j) Gfx::draw(schoolIcon, topLeftX[index]+1+6*j, curY+6+1); if (toDo < 20) Gfx::drawClipped(LSI(SPELLS,10), topLeftX[index]+1+toDo*6+4, curY+6, 1+toDo*6+4, ROW_HEIGHT*i+6, 0, 6); if (turns > 20) { toDo = std::min(turns-20, 20); for (int j = 0; j < toDo; ++j) Gfx::draw(schoolIcon, topLeftX[index]+1+6*j, curY+12+1); if (toDo < 20) Gfx::drawClipped(LSI(SPELLS,10), topLeftX[index]+1+toDo*6+4, curY+12, 1+toDo*6+4, ROW_HEIGHT*i+6, 0, 6); } else Gfx::drawClipped(LSI(SPELLS,10), topLeftX[index], curY+12, 0, ROW_HEIGHT*i+6, 0, 6); } else { Gfx::draw(schoolIcon, topLeftX[index]+1, curY+6+1); // TODO: localize int w = 0; if (!combatMode) w = Fonts::drawString("Instant", FontFaces::Small::BROWN, topLeftX[index]+8, curY+6, ALIGN_LEFT); Gfx::drawClipped(LSI(SPELLS,10), topLeftX[index]+9+w+4, curY+6, 9+w+4, ROW_HEIGHT*i+6, 0, 6); Gfx::drawClipped(LSI(SPELLS,10), topLeftX[index], curY+12, 0, ROW_HEIGHT*i+6, 0, 6); } } } }
void SpellBookView::draw() { Gfx::draw(LSI(SPELLS,0), 16, 11); drawPage(0); drawPage(1); }
void ResearchView::draw() { // backdrop Gfx::draw(LSI(SCROLL,6), 0, 0); // prevpage / nextpage buttons int sx = 24, sy = 27; int dy = 37, dx = 148; const BookView::Page* pages[] = { book->current(), book->current(1) }; for (int i = 0; i < 8; ++i) { const BookView::Page* page = pages[i/4]; if (!page) continue; const ResearchStatus& status = page->at(i%4); if (status.spell) { int tx = sx + dx*(i/4); int ty = sy + dy*(i%4); const Spell* s = status.spell; int turns = 0; int manaCost = 0; const FontSpriteSheet* fonts[2]; const Palette* map = nullptr; if (!status.discovered || page->isResearch()) { turns = player->book()->turnsToCompleteResearch(s); if (status.spell == player->book()->getCurrentResearch()) { map = FontFaces::Palettes::BLINK_WHITE_BLUE; turns = player->book()->turnsToCompleteResearch(); } else { map = nullptr; turns = player->book()->turnsToCompleteResearch(s); } } else { manaCost = s->mana.manaCost != -1 ? s->mana.manaCost : s->mana.combatManaCost; turns = manaCost / player->castingSkill() + (manaCost % player->castingSkill() != 0 ? 1 : 0); } if (status.discovered) { fonts[0] = FontFaces::Serif::DARK_BROWN; fonts[1] = FontFaces::Tiny::BROWN; } else { fonts[0] = FontFaces::Crypt::SERIF_BROWN; fonts[1] = FontFaces::Crypt::TINY_BROWN; } Fonts::drawString(i18n::s(s->name), fonts[0], tx, ty, ALIGN_LEFT); if (!status.discovered || page->isResearch()) Fonts::drawStringBounded(Fonts::format("Research Cost:%d (%d turns)", s->mana.researchCost, turns), fonts[1], tx, ty+11, 125, ALIGN_LEFT, map); else Fonts::drawStringBounded(Fonts::format("Casting Cost:%d (%d turns)", manaCost, turns), fonts[1], tx, ty+11, 125, ALIGN_LEFT, map); //TODO: real descs std::string descs[] = { "Increases target unit's melee attack strength by 1", "Dispels enemy spells on one unit in combat.", "Moves the location of your Summoning Circle to another city.", "Research Cost:190 (64 turns)\nEndows a unit with the ability to walk on water.", "Fully reveals terrain, terrain special, and cities on all squares in a targeted 'map window.'", "Dispels all enemy spells in the taget map square.", "Reveals the spell currently being cast by opponent wizards.", "Summons a lesser hero to lead your army." }; Fonts::drawStringBounded(descs[i], FontFaces::Tiny::BROWN, tx, ty+11+6, 125, ALIGN_LEFT, map); } } }
void CityView::draw() { CityLayout::draw(city, player); /* draw minimap */ Viewport::drawCityViewport(player, g->world, city->getPosition()); Gfx::draw(LSI(BACKGRND, 6), 0, 0); // bg /* city name*/ std::string cityName = fmt::sprintf("%s of %s", i18n::c(i18n::CITY_SIZE_NAMES[city->tileSize()]), city->getName()); Fonts::drawString(cityName, FontFaces::Huge::GOLD, 104, 2, ALIGN_CENTER); const auto& labourGfx = GfxData::raceGfxSpec(city->race); int popX = 4, reqFarmers = city->reservedPopulation; for (int i = 0; i < (city->population / 1000); ++i) { if (i < reqFarmers) Gfx::draw(labourGfx.cityFarmer, popX, 27); else if (i < reqFarmers + city->farmers) Gfx::draw(labourGfx.cityFarmer, popX, 27); else Gfx::draw(labourGfx.cityWorker, popX, 27); if (i == reqFarmers - 1) popX += 4; popX += 9; } int sx = 6; int sy = 52; //TODO: spacing between icons still incorrect sx += drawCityProp(city->necessaryFood, UpkeepSymbol::FOOD, sx, sy) + 5; drawCityProp(city->food, UpkeepSymbol::FOOD, sx, sy); sx = 6; sy += 8; drawCityProp(city->work, UpkeepSymbol::WORK, sx, sy); sx = 6; sy += 8; sx += drawCityProp(city->upkeep.gold, UpkeepSymbol::GOLD, sx, sy) + 5; drawCityProp(city->gold, UpkeepSymbol::GOLD, sx, sy); sx = 6; sy += 8; drawCityProp(city->magicPower, UpkeepSymbol::MANA, sx, sy); sx = 6; sy += 8; drawCityProp(city->knowledge, UpkeepSymbol::RESEARCH, sx, sy); Army* army = g->world->get(city->getPosition())->army; if (army) { for (int i = 0; i < army->size(); ++i) { const Unit* u = army->get(i); //if (!army.isPatrol()) UnitDraw::drawStatic(u, 215+20*(i%5), 102+17*(i/5), true, false); } } /* draw city info: race and population */ Fonts::drawString(i18n::s(GfxData::raceGfxSpec(city->race).name), FontFaces::Small::YELLOW, 5, 18, ALIGN_LEFT); //TODO: localize digits Fonts::drawString(fmt::sprintf("Population: %s (+%d)", strings::groupDigits(city->population), city->growthRate), FontFaces::Small::YELLOW, 209, 18, ALIGN_RIGHT); const Productable* production = city->getProductable(); /* draw current production */ if (production == Building::HOUSING || production == Building::TRADE_GOODS) { Gfx::draw(LSI(BACKGRND, 13), 260, 149); CityLayout::drawBuildingCentered(city, static_cast<const Building*>(production), 217, 179); /* TODO: localize and center align */ if (production == Building::HOUSING) Fonts::drawStringBounded("Increases population growth rate.", FontFaces::Tiny::WHITE, 286, 158, 50, ALIGN_CENTER); else if (production == Building::TRADE_GOODS) Fonts::drawStringBounded("Converts production to gold.", FontFaces::Tiny::WHITE, 286, 158, 50, ALIGN_CENTER); } else { if (production->productionType() == Productable::Type::BUILDING) { CityLayout::drawBuildingCentered(city, static_cast<const Building*>(city->getProductable()), 217, 177); } else if (production->productionType() == Productable::Type::UNIT) { UnitDraw::drawUnitIso(static_cast<const UnitSpec*>(production), 218, 144, nullptr, player); } /* compute and draw missing turns to complete production */ /* TODO: localize */ int turns = g->cityMechanics.turnsRequiredForProduction(city); Fonts::drawString(fmt::format("{} Turn{}", turns, (turns == 1 ? "" : "s")), FontFaces::Small::YELLOW, 316, 139, ALIGN_RIGHT); /* draw production coins */ int max = 10; for (int i = 0; i < std::min(production->productionCost()/10, 40); ++i) { /* TODO: fixare il draw parziale delle monete */ if (i*10 < city->productionPool) Gfx::draw(LSI(BACKGRND, 12), 262+i%max*5, 151+i/max*7); else Gfx::draw(LSI(BACKGRND, 11), 262+i%max*5, 151+i/max*7); } } /* TODO: in realtà il font sarebbe obreggiato dall'alto / gestire wrapping nomi lunghi (ship wrights guild etc) */ if (Fonts::stringWidth(FontFaces::Small::WHITE, production->productionName()) < 40) Fonts::drawString(production->productionName(), FontFaces::Small::WHITE, 237, 178, ALIGN_CENTER); else Fonts::drawString(production->productionName(), FontFaces::Tiny::WHITE, 235, 177, ALIGN_CENTER); /* draw city enchantments */ const auto spells = city->getSpells(); auto it = spells.begin(); std::advance(it, cityEnchantPage*CITY_ENCHANT_PER_PAGE); for (int i = 0; i < CITY_ENCHANT_PER_PAGE && it != spells.end(); ++i, ++it) { const auto& cast = *it; assert(cast.caster().isWizard()); const FontSpriteSheet* face = Fonts::fontForColor(cast.caster().player()->color); //Fonts::drawString(i18n::s(cast.spell->name), face, 138, 50+7*i, ALIGN_LEFT); Fonts::drawString(fmt::sprintf("%s%d", i18n::s(cast.spell()->name), cityEnchantPage*CITY_ENCHANT_PER_PAGE + i), face, 138, 50+7*i, ALIGN_LEFT); } }
MainView::MainView(ViewManager *gvm) : View(gvm), hoveredTile(nullptr) { buttons.resize(BUTTON_COUNT); buttons[GAME] = Button::buildBistate("Game", 7, 4, LSI(MAIN, 1)); buttons[SPELLS] = Button::buildBistate("Spells", 47, 4, LSI(MAIN, 2)); buttons[ARMIES] = Button::buildBistate("Armies", 89, 4, LSI(MAIN, 3)); buttons[CITIES] = Button::buildBistate("Cities", 140, 4, LSI(MAIN, 4)); buttons[MAGIC] = Button::buildBistate("Magic", 184, 4, LSI(MAIN, 5)); buttons[INFO] = Button::buildBistate("Info", 226, 4, LSI(MAIN, 6)); buttons[PLANE] = Button::buildBistate("Plane", 270, 4, LSI(MAIN, 7)); buttons[NEXT] = Button::buildPressedOnly("Next", 246, 178, LSI(MAIN, 58)); buttons[DONE] = Button::buildTristate("Done", 246, 176, LSI(MAIN, 8), LSI(MAIN,12)); buttons[PATROL] = Button::buildTristate("Patrol", 280, 176, LSI(MAIN, 9), LSI(MAIN,13)); buttons[WAIT] = Button::buildTristate("Wait", 246, 186, LSI(MAIN, 10), LSI(MAIN,14)); buttons[BUILD_ROAD] = Button::buildTristate("Build", 280, 186, LSI(MAIN, 11), LSI(MAIN,15)); buttons[BUILD_OUTPOST] = Button::buildTristate("Build", 280, 186, LSI(MAIN, 11), LSI(MAIN,15)); buttons[PURIFY] = Button::buildTristate("Purify", 280, 186, LSI(MAIN, 42), LSI(MAIN, 43)); buttons[MELD] = Button::buildBistate("Meld", 280, 186, LSI(MAIN, 49)); buttons[ROAD_OK] = Button::buildBistate("Road Ok", 246, 181, LSI(MAIN, 46)); buttons[ROAD_CANCEL] = Button::buildBistate("Road Cancel", 280, 181, LSI(MAIN, 41)); buttons[SURVEYOR_CANCEL] = Button::buildBistate("surveyor cancel", 263, 181, LSI(MAIN, 41)); buttons[SPELLCAST_CANCEL] = Button::buildBistate("spellcast cancel", 263, 181, LSI(MAIN, 41)); // CANCEL BUTTON MISSING buttons[GAME]->setAction([gvm](){ gvm->switchView(VIEW_LOAD); }); buttons[SPELLS]->setAction([gvm](){ gvm->switchOverview(VIEW_SPELL_BOOK); }); buttons[MAGIC]->setAction([gvm](){ gvm->switchView(VIEW_MAGIC); }); buttons[ARMIES]->setAction([gvm](){ gvm->switchView(VIEW_ARMIES); }); buttons[CITIES]->setAction([gvm](){ gvm->switchView(VIEW_CITIES); }); buttons[INFO]->setAction([gvm](){ gvm->switchOverview(VIEW_INFO_MENU); }); buttons[PLANE]->setAction([this](){ player->switchPlane(); switchToNormalState(); }); buttons[NEXT]->setAction([this](){ LocalGame::i->getGame()->nextTurn(); switchToNormalState(); }); buttons[SURVEYOR_CANCEL]->setAction([this]() { switchToNormalState(); }); buttons[SPELLCAST_CANCEL]->setAction([this]() { g->cancelCast(player); switchToNormalState(); }); buttons[DONE]->setAction([this](){ switchToNormalState(); }); /*if (player.selectedArmy() != null && player.selectedRoute() != null && !player.selectedRoute().completed()) player.saveRoute();*/ buttons[PATROL]->setAction([this](){ player->getSelectedArmy()->patrol(); switchToNormalState(); }); buttons[BUILD_OUTPOST]->setAction([this](){ g->settleCity(player->getSelectedArmy(), "Test"); player->resetArmy(); }); buttons[BUILD_ROAD]->setAction([this](){ switchToRoadBuilding(); }); buttons[ROAD_CANCEL]->setAction([this](){ switchToUnitSelection(player->getSelectedArmy()); }); buttons[ROAD_OK]->setAction([this](){ /* TODO */ }); for (const auto e : { DONE,PATROL,WAIT,BUILD_ROAD,BUILD_OUTPOST,PURIFY,MELD,SURVEYOR_CANCEL,SPELLCAST_CANCEL,ROAD_OK,ROAD_CANCEL } ) buttons[e]->hide(); buttons[BUILD_OUTPOST]->deactivate(); substate = MAIN; }
void MainView::draw() { if (substate != SPELL_CAST && player->getSpellTarget() != Target::NONE) switchToSpellCast(); else if (substate == SPELL_CAST && player->getSpellTarget() == Target::NONE) switchToNormalState(); Gfx::draw(main_backdrop, 0, 0); const Army* army = player->getSelectedArmy(); if (substate == UNIT) { for (int j = 0; j < army->size(); ++j) { Unit *unit = army->get(j); int x = 246+23*(j%3), y = 78+29*(j/3); Gfx::draw(LSI(MAIN,24).relative(j), x, y); UnitDraw::drawStatic(unit, x+1, y+1, player->isSelectedUnit(unit), false); /* draw unit level */ UnitDraw::drawUnitLevel(unit->getExperienceLevel(), x + 3, y + 22, 4, false); } /* compute and draw movement of current selection */ value_t moves = player->selectedAvailMoves(); if (moves > 0) { Fonts::drawString(fmt::sprintf("Moves: %s", UnitDraw::stringForDoubleMovement(moves)), FontFaces::Small::WHITE, 245, 166, ALIGN_LEFT); movement_list movement = player->selectedArmyMovementType(); /* draw movement icons */ if (movement.size() > 0) { size_t i = 0; bool hasFlying = movement.contains(MovementType::FLYING); for (const auto& effect : movement) { //TODO: maybe this should be decided by the algorithm which computes the movement type if (effect == MovementType::SWIMMING && hasFlying) continue; Gfx::draw(movementIconForType(effect), 306-10*i++, 167); } } else Gfx::draw(movementIconForType(MovementType::NORMAL), 306, 167); } } else if (substate == ROAD_BUILDING) { Gfx::draw(right_backdrop_road, 240, 76); Gfx::draw(road_buttons_backdrop, 240, 76 + 97); Fonts::drawString("Road", FontFaces::Serif::WHITE_SURVEY, 280, 79, ALIGN_CENTER); Fonts::drawString("Building", FontFaces::Serif::WHITE_SURVEY, 279, 89, ALIGN_CENTER); Fonts::setFace(FontFaces::Small::YELLOW_PALE, 1, 0); s16 turnsRequired = 6; Fonts::drawStringBounded(fmt::sprintf("It will take %d turns to complete the construction of this road", turnsRequired), 249, 105, 50, ALIGN_LEFT); //TODO: management of multiple road by clicking } else if (substate == SURVEYOR) { Gfx::draw(right_backdrop_survey, 240, 76); Gfx::draw(cancel_button_backdrop, 240, 76 + 97); surveyor.draw(); } else if (substate == SPELL_CAST) { Gfx::draw(right_backdrop_cast, 240, 76); Gfx::draw(cancel_button_backdrop, 240, 76 + 97); Fonts::drawString("Casting", FontFaces::Serif::WHITE_SURVEY, 240+6+8+4, 76+2+1, ALIGN_LEFT); //TODO: colors etc Fonts::setFace(FontFaces::Small::YELLOW); Fonts::setVerSpace(2); Fonts::drawStringBounded("^wSelect a friendly unit as the target for a ^yBless^^ ^wspell", 119, 49, 64, ALIGN_LEFT); } else { Gfx::draw(right_backdrop_main, 240, 76); Gfx::draw(next_button_backdrop, 240, 76+97); } Viewport::drawMainViewport(player, g->world); //Fonts.drawStringBounded("This shows the current city and the surrounding area. The city does not control/work the darkened corners. If a nearby city and this city control the same square, each city receives only half of the square's value.", Fonts.Face.TEAL_SMALL, 20, 30, 173, Fonts.Align.CENTER); const Position vp = player->getViewport(); Viewport::drawMicroMap(player, 251, 21, 58, 30, vp.x, vp.y, vp.plane); // 58, 30 Gfx::drawClipped(TSI(UNIT_DETAIL_SPECIAL_THINGS,0,0), 251 + 58/2 - 7, 21 + 30/2 - 6, 59, 0, 14, 12); if (substate == MAIN) { int gg = player->goldDelta(), f = player->foodDelta(), m = player->manaDelta(); Fonts::drawString(fmt::sprintf("%d Gold",gg), gg > 0 ? FontFaces::Tiny::YELLOW_STROKE : FontFaces::Tiny::RED_STROKE, 277, 100, ALIGN_CENTER); Fonts::drawString(fmt::sprintf("%d Food",f), f > 0 ? FontFaces::Tiny::YELLOW_STROKE : FontFaces::Tiny::RED_STROKE, 277, 132, ALIGN_CENTER); Fonts::drawString(fmt::sprintf("%d Mana",m), m > 0 ? FontFaces::Tiny::YELLOW_STROKE : FontFaces::Tiny::RED_STROKE, 277, 164, ALIGN_CENTER); } if (substate == MAIN || substate == UNIT || substate == ROAD_BUILDING || substate == SURVEYOR) { Fonts::drawString(Fonts::format("%d",player->totalGoldPool()), FontFaces::Small::WHITE, 266, 67, ALIGN_RIGHT); Fonts::drawString("GP", FontFaces::Tiny::WHITE, 267, 67, ALIGN_LEFT); Fonts::drawString(Fonts::format("%d",player->totalManaPool()), FontFaces::Small::WHITE, 304, 67, ALIGN_RIGHT); Fonts::drawString("MP", FontFaces::Tiny::WHITE, 305, 67, ALIGN_LEFT); } #if defined(DEBUG) { u32 turns = g->getTurnCount(); const auto& players = g->getPlayers(); auto it = std::find(players.begin(), players.end(), g->currentPlayer()); size_t indexOfCurrentPlayer = std::distance(players.begin(), it); auto it2 = std::find(players.begin(), players.end(), player); size_t indexOfViewPlayer = std::distance(players.begin(), it2); Fonts::drawString(Fonts::format("t %u gp %zu vp %zu %d,%d", turns, indexOfCurrentPlayer, indexOfViewPlayer, hoveredTile ? hoveredTile->x() : -1, hoveredTile ? hoveredTile->y() : -1), FontFaces::Tiny::WHITE_STROKE, 0, HEIGHT-10, ALIGN_LEFT); } #endif }
void ArmyView::draw() { s16 i = army->size(); s16 h = 24 + i*19; s16 o = (200-(h+5))/2; const auto& propGfx = GfxData::propGfx(); Gfx::drawClipped(LSI(UNITVIEW, 28), 41, o, 0, 0, 238, h); Gfx::draw(LSI(UNITVIEW, 29), 41, o + h); const int PROP_BOX_DELTA = 20; int c = 24; for (int j = 0; j < i; ++j) { const int y = c + o; const Unit* unit = army->get(j); UnitDraw::drawStatic(unit, 49, y, true, false); Fonts::drawString(unit->name(), FontFaces::Medium::TEAL_STROKE, 72, y + 4, ALIGN_LEFT); /* TODO: should they be spec values of computed values (with bonuses and such) */ const MeleeInfo melee = unit->getMeleeInfo(); const RangedInfo ranged = unit->getRangedInfo(); const prop_value shields = unit->getProperty(Property::SHIELDS); const prop_value hits = unit->getProperty(Property::HIT_POINTS); const MovementInfo movement = unit->getMovementInfo(); if (melee.strength > 0) { const int BASE = 182 + PROP_BOX_DELTA*0; Gfx::draw(propGfx[melee.type].blueBoxed, propPalette.get(), BASE, y + 5); Fonts::drawString(std::to_string(melee.strength), FontFaces::Small::TEAL_DARK, BASE, y + 6, ALIGN_RIGHT); } /* TODO: manage schools according to option */ if (ranged.isPresent()) { const int BASE = 182 + PROP_BOX_DELTA*1; Gfx::draw(propGfx[ranged.type].blueBoxed, propPalette.get(), BASE, y + 5); Fonts::drawString(std::to_string(melee.strength), FontFaces::Small::TEAL_DARK, BASE, y + 6, ALIGN_RIGHT); } { const int BASE = 182 + PROP_BOX_DELTA*2; Gfx::draw(propGfx[Property::SHIELDS].blueBoxed, propPalette.get(), BASE, y + 5); Fonts::drawString(std::to_string(shields), FontFaces::Small::TEAL_DARK, BASE, y + 6, ALIGN_RIGHT); } { const int BASE = 182 + PROP_BOX_DELTA*3; Gfx::draw(propGfx[Property::HIT_POINTS].blueBoxed, propPalette.get(), BASE, y + 5); Fonts::drawString(std::to_string(hits), FontFaces::Small::TEAL_DARK, BASE, y + 6, ALIGN_RIGHT); } { const int BASE = 182 + PROP_BOX_DELTA*4; Gfx::draw(propGfx[movement.type].blueBoxed, propPalette.get(), BASE, y + 5); Fonts::drawString(std::to_string(movement.moves), FontFaces::Small::TEAL_DARK, BASE, y + 6, ALIGN_RIGHT); } c += 16+3; } //Texture.drawClipped(texture, x, y, fx, fy, w, h) }
/* !DO NOT ALTER FUNCTION SIGNATURE! */ int callback_ofc_capable_switch_ofc_logical_switches_ofc_switch_ofc_resources_ofc_port (void ** data, XMLDIFF_OP op, xmlNodePtr node, struct nc_err** error) { nc_verb_verbose("%s: data=%p, op=%d\n", __PRETTY_FUNCTION__, data, op); print_element_names(node, 0); // retrieve the dpid of this twig xmlNodePtr tmp = find_element(BAD_CAST "datapath-id", node->parent->parent->children); assert(tmp); uint64_t dpid = parse_dpid(tmp->children->content); int rv = EXIT_SUCCESS; // fixme depending on the erropt (e.g. NC_EDIT_ERROPT_ROLLBACK we might still have *data set) assert(data); if (NULL == *data) { *data = calloc(1, sizeof(struct lsi)); assert(*data); } if (XMLDIFF_ADD & op) { xmlChar buf[255]; // check if port is already attached xmlStrPrintf(buf, sizeof(buf), "/ofc:capable-switch/ofc:logical-switches/ofc:switch/ofc:resources/ofc:port[text()='%s']", XML_GET_CONTENT(node->children)); xmlXPathObjectPtr xpath_obj_ptr = get_node(node->doc, namespace_mapping, buf); assert(xpath_obj_ptr); assert(xpath_obj_ptr->nodesetval); if (1 == xpath_obj_ptr->nodesetval->nodeNr) { if (NULL == LSI(data)->res.port_list_add) { LSI(data)->res.port_list_add = list_new(); assert(((struct lsi* )*data)->res.port_list_add); } struct port *p = calloc(1, sizeof(struct port)); p->resource_id = xmlNodeListGetString(node->doc, node->children, 1); p->op = ADD; p->dpid = dpid; list_append_data(LSI(data)->res.port_list_add, p); nc_verb_verbose("added to list: dpid=%lx port %s with op=%u\n", p->dpid, p->resource_id, p->op); } else { // nodeNr > 1 ==> already attached port nc_verb_verbose("attachment failed dpid=%lx port %s: port already attached.\n", dpid, XML_GET_CONTENT(node->children)); rv = EXIT_FAILURE; } xmlXPathFreeObject(xpath_obj_ptr); } else if (XMLDIFF_REM & op) { if (NULL == LSI(data)->res.port_list_del) { LSI(data)->res.port_list_del = list_new(); assert(((struct lsi* ) *data)->res.port_list_del); } struct port *p = calloc(1, sizeof(struct port)); p->resource_id = xmlNodeListGetString(node->doc, node->children, 1); p->op = DELETE; p->dpid = dpid; list_append_data(LSI(data)->res.port_list_del, p); nc_verb_verbose("added to list: dpid=%lx port %s with op=%u\n", p->dpid, p->resource_id, p->op); } else { // todo implement nc_verb_error("not implemented"); assert(0); } return rv; }
/* !DO NOT ALTER FUNCTION SIGNATURE! */ int callback_ofc_capable_switch_ofc_logical_switches_ofc_switch (void ** data, XMLDIFF_OP op, xmlNodePtr node, struct nc_err** error) { nc_verb_verbose("%s: data=%p, op=%d\n", __PRETTY_FUNCTION__, data, op); print_element_names(node, 0); if (NULL == ofc_state.lsi_list) { ofc_state.lsi_list = list_new(); assert(ofc_state.lsi_list); } assert(data); assert(*data); if (!(XMLDIFF_REM & op)) { list_append_data(ofc_state.lsi_list, *data); } int rv = EXIT_SUCCESS; if (XMLDIFF_ADD & op) { assert(XMLDIFF_CHAIN & op); nc_verb_verbose("create new lsi (dpid=%lu, name=%s)\n", LSI(data)->dpid, LSI(data)->dpname); if (lsi_create(ofc_state.xmp_client_handle, *data)) { rv = EXIT_FAILURE; } } else if (XMLDIFF_REM& op) { assert(XMLDIFF_CHAIN & op); nc_verb_verbose("destroy lsi (dpid=%lu, name=%s)\n", LSI(data)->dpid, LSI(data)->dpname); if ( lsi_destroy(ofc_state.xmp_client_handle, LSI(data)->dpid) ) { rv = EXIT_FAILURE; } // cannot have a port add during a lsi destroy assert(NULL == LSI(data)->res.port_list_add); // check if there were ports attached, then clean the list, because detachment takes place during lsi destruction if (NULL != LSI(data)->res.port_list_del) { struct port *p; while ((p = list_pop_head(LSI(data)->res.port_list_del))) { xmlFree(p->resource_id); free(p); } } // no need to deal with controllers seperately here lsi_cleanup(*data); } else if (XMLDIFF_MOD & op) { // direct sub elements changed nc_verb_error("not implemented XMLDIFF_MOD"); assert(0); } else if (XMLDIFF_CHAIN & op) { // resources or controllers changed (attachment of ports handled in parent) nc_verb_verbose("XMLDIFF_CHAIN\n"); // check dpid if (0 == LSI(data)->dpid) { xmlNodePtr tmp = find_element(BAD_CAST "datapath-id", node->children); assert(tmp); uint64_t dpid = parse_dpid(tmp->children->content); if (LSI(data)->dpid != dpid) { LSI(data)->dpid = dpid; } } if (LSI(data)->controller_list_add) { lsi_connect_to_controller(ofc_state.xmp_client_handle, LSI(data)); } if (LSI(data)->controller_list_del) { // fixme implement // assert(0); } } else { nc_verb_error("unsupported op"); assert(0); } *data = NULL; return rv; }