3#include <Tempest/Painter>
4#include <Tempest/SoundEffect>
16using namespace Tempest;
36 for(
size_t i=0; i<
id && it.isValid(); ++i)
41 virtual bool is(
const Inventory* i)
const {
return i==
nullptr; }
87 columsCount = size_t(invMaxColumns);
else
90 setFocusPolicy(NoFocus);
91 setCursorShape(CursorShape::Hidden);
92 takeTimer.timeout.bind(
this,&InventoryMenu::onTakeStuff);
104 renderer.
reset(
true);
249void InventoryMenu::processMove(KeyEvent& e) {
250 auto key = keycodec.
tr(e);
261void InventoryMenu::moveLeft(
bool usePage) {
262 auto& sel = activePageSel();
264 if(usePage && sel.sel%columsCount==0 && page>0)
270void InventoryMenu::moveRight(
bool usePage) {
271 auto& pg = activePage();
272 auto& sel = activePageSel();
273 const size_t pCount = pagesCount();
275 if(usePage && ((sel.sel+1u)%columsCount==0 || sel.sel+1u==pg.size() || pg.size()==0) && page+1u<pCount)
277 else if(sel.sel+1<pg.size())
281void InventoryMenu::moveUp() {
282 auto& sel = activePageSel();
284 if(sel.sel>=columsCount)
285 sel.sel -= columsCount;
290void InventoryMenu::moveDown() {
291 auto& pg = activePage();
292 auto& sel = activePageSel();
294 if(sel.sel+columsCount<pg.size())
295 sel.sel += columsCount;
310 takeTimer.start(200);
316 else if((KeyEvent::K_3<=e.key && e.key<=KeyEvent::K_9) || e.key==KeyEvent::K_0) {
318 if((KeyEvent::K_3<=e.key && e.key<=KeyEvent::K_9))
319 slot = uint8_t(e.key-KeyEvent::K_0);
325 else if(e.key==KeyEvent::K_Space) {
327 takeTimer.start(200);
330 else if(e.key==KeyEvent::K_Z) {
332 takeTimer.start(200);
335 else if(e.key==KeyEvent::K_X) {
337 takeTimer.start(200);
367 if (e.button==MouseEvent::ButtonLeft)
369 else if (e.button==MouseEvent::ButtonRight)
389 scrollDelta += e.delta;
391 for(
int i=0;i<scrollDelta/120;++i)
395 for(
int i=0;i<-scrollDelta/120;++i)
402const World *InventoryMenu::world()
const {
406size_t InventoryMenu::rowsCount()
const {
408 return size_t((h()-iy-infoHeight()-20)/slotSize().h);
428Size InventoryMenu::slotSize()
const {
431 return Size(
int(cell*scale),
int(cell*scale));
434int InventoryMenu::infoHeight()
const {
439size_t InventoryMenu::pagesCount()
const {
447 return *(page==0 ? pageOth : pagePl);
455InventoryMenu::PageLocal &InventoryMenu::activePageSel() {
457 return (page==0 ? pageLocal[0] : pageLocal[1]);
461void InventoryMenu::onItemAction(uint8_t slotHint) {
462 auto& page = activePage();
463 auto& sel = activePageSel();
465 auto it = page.get(sel.sel);
470 const size_t clsId = it->clsId();
474 player->
useItem(clsId,slotHint,
false);
475 auto it2 = page.get(sel.sel);
476 if((!it2.isValid() || it2->clsId()!=clsId) && sel.sel>0)
482 takeTimer.start(200);
487void InventoryMenu::onTakeStuff() {
488 size_t itemCount = 0;
489 auto& page = activePage();
490 auto& sel = activePageSel();
491 if(sel.sel >= page.size())
493 auto it = page.get(sel.sel);
496 itemCount = uint32_t(std::pow(10,takeCount / 10));
497 if(it.count() <= itemCount) {
498 itemCount = uint32_t(it.count());
503 itemCount = it.count();
512 if(it.count() < itemCount) {
513 itemCount = it.count();
518 player->
moveItem(it->clsId(),*chest,itemCount);
520 player->
addItem (it->clsId(),*chest,itemCount);
525 player->
sellItem(it->clsId(),*trader,itemCount);
527 player->
buyItem (it->clsId(),*trader,itemCount);
532 player->
addItem(it->clsId(),*trader,itemCount);
536 player->
dropItem(it->clsId(),itemCount);
541void InventoryMenu::adjustScroll() {
542 auto& page = activePage();
543 auto& sel = activePageSel();
544 sel.sel = std::min(sel.sel, std::max<size_t>(page.size(),1)-1);
545 while(sel.sel<sel.scroll*columsCount) {
553 const size_t hcount=rowsCount();
554 while(sel.sel>=(sel.scroll+hcount)*columsCount) {
559void InventoryMenu::drawAll(Painter &p,
Npc &player, DrawPass pass) {
567 const int wcount = int(columsCount);
568 const int hcount = int(rowsCount());
573 drawItems(p,pass,*pageOth,pageLocal[0],padd,iy,wcount,hcount);
576 if(trader!=
nullptr) {
579 drawItems(p,pass,*pageOth,pageLocal[0],padd,iy,wcount,hcount);
584 drawGold (p,player,w()-padd-2*slotSize().w,70);
585 drawItems(p,pass,*pagePl,pageLocal[1],w()-padd-wcount*slotSize().w,iy,wcount,hcount);
592void InventoryMenu::drawItems(Painter &p, DrawPass pass,
593 const Page &inv,
const PageLocal& sel,
int x0,
int y,
int wcount,
int hcount) {
599 p.drawRect(x0,y,slotSize().w*wcount,slotSize().h*hcount,
600 0,0,tex->w(),tex->h());
603 auto it = inv.iterator();
605 for(
size_t i=0; it.isValid() && i<sel.scroll*
size_t(wcount); ++i) {
609 for(
int i=0;i<hcount;++i) {
610 for(
int r=0;r<wcount;++r) {
611 const int x = x0 + r*slotSize().w;
614 p.drawRect(x,y,slotSize().w,slotSize().h,
615 0,0,slot->w(),slot->h());
618 drawSlot(p,pass, it,inv,sel, x,y,
id);
628 const Page& page,
const PageLocal &sel,
629 int x,
int y,
size_t id) {
633 auto& active = activePage();
637 if((!it.
isValid() &&
id==0) || (
id==sel.sel && &page==&active)){
639 p.drawRect(x,y,slotSize().w,slotSize().h,
640 0,0,selT->w(),selT->h());
645 p.drawRect(x,y,slotSize().w,slotSize().h,
646 0,0,selU->w(),selU->h());
649 const int dsz = (
id==sel.sel ? 5 : 0);
650 renderer.
drawItem(x-dsz, y-dsz, slotSize().w+2*dsz, slotSize().h+2*dsz, *it);
656 auto sz = fnt.textSize(vint);
657 fnt.drawText(p,x+slotSize().w-sz.w-10,
666 auto sz = fnt.textSize(vint);
668 y+slotSize().h/2+sz.h/2,
674void InventoryMenu::drawGold(Painter &p,
Npc &player,
int x,
int y) {
678 auto txt = w ? w->script().currencyName() :
"";
679 const size_t gold = player.
inventory().goldCount();
684 drawHeader(p,vint,x,y);
687void InventoryMenu::drawHeader(Painter &p, std::string_view title,
int x,
int y) {
691 const int tw = fnt.textSize(title).w;
692 const int th = fnt.textSize(title).h;
693 const int padd = int(8*scale);
694 const int dw = std::max(slotSize().w*2, tw+padd*2);
695 const int dh = int(34*scale);
699 p.drawRect(x,y,dw,dh, 0,0,tex->w(),tex->h());
703 p.drawRect(x,y,dw,dh, 0,0,slot->w(),slot->h());
706 fnt.drawText(p,x+(dw-tw)/2,y+dh/2+th/2,title);
709void InventoryMenu::drawInfo(Painter &p) {
711 const int dw = std::min(w(),
int(720*scale));
712 const int dh = infoHeight();
713 const int x = (w()-dw)/2;
714 const int y = h()-dh-20;
716 auto& pg = activePage();
717 auto& sel = activePageSel();
719 auto it = pg.get(sel.sel);
723 auto& r = *pg.get(sel.sel);
726 p.drawRect(x,y,dw,dh,
727 0,0,tex->w(),tex->h());
731 auto desc = r.description();
732 int tw = fnt.textSize(desc).w;
734 fnt.drawText(p,x+(dw-tw)/2,y+
int(fnt.pixelSize()),desc);
737 auto txt = r.uiText(i);
738 int32_t val = r.uiValue(i);
748 int tw = fnt.textSize(vint).w;
750 fnt.drawText(p, x+20, y+
int(i+2)*fnt.pixelSize(), txt);
752 fnt.drawText(p,x+dw-tw-20,y+
int(i+2)*fnt.pixelSize(),vint);
756 renderer.
drawItem(x+dw-sz-sz/2,y,sz,sz,r);
static auto options() -> const Options &
static float interfaceScale(const Tempest::Widget *w)
const World * world() const
static int settingsGetI(std::string_view sec, std::string_view name)
void emitGlobalSound(std::string_view sfx)
std::string_view displayName() const
bool needToLockpick(const Npc &pl) const
void reset(bool full=false)
void draw(Tempest::Encoder< Tempest::CommandBuffer > &cmd)
void drawItem(int x, int y, int w, int h, const Item &item)
Iterator iterator(IteratorType t) const
Action tr(Tempest::KeyEvent const &e) const
auto weaponState() const -> WeaponState
void stopAnim(std::string_view ani)
void moveItem(size_t id, Interactive &to, size_t count=1)
void unequipItem(size_t item)
auto inventory() const -> const Inventory &
auto interactive() const -> Interactive *
void dropItem(size_t id, size_t count=1)
bool closeWeapon(bool noAnim)
std::string_view displayName() const
void buyItem(size_t id, Npc &from, size_t count=1)
void useItem(size_t item)
void sellItem(size_t id, Npc &to, size_t count=1)
bool setInteraction(Interactive *id, bool quick=false)
Item * addItem(size_t id, size_t amount)
BodyState bodyStateMasked() const
static const GthFont & font(const float scale)
static const Tempest::Texture2d * loadTexture(std::string_view name, bool forceMips=false)