GUI template/macro usage refactor.

pull/28/head
sigonasr2 12 months ago
parent a1caeff702
commit e744112206
  1. 3
      Crawler/CREDITS
  2. 4
      Crawler/CharacterAbilityPreviewComponent.h
  3. 36
      Crawler/CharacterInfoWindow.cpp
  4. 276
      Crawler/CharacterMenuWindow.cpp
  5. 4
      Crawler/CharacterRotatingDisplay.h
  6. 49
      Crawler/ClassSelectionWindow.cpp
  7. 6
      Crawler/Crawler.cpp
  8. 6
      Crawler/Crawler.vcxproj
  9. 9
      Crawler/Crawler.vcxproj.filters
  10. 7
      Crawler/EncountersSpawnListScrollableWindowComponent.h
  11. 4
      Crawler/EquipSlotButton.h
  12. 22
      Crawler/InventoryConsumableWindow.cpp
  13. 7
      Crawler/InventoryScrollableWindowComponent.h
  14. 49
      Crawler/InventoryWindow.cpp
  15. 27
      Crawler/ItemLoadoutWindow.cpp
  16. 48
      Crawler/LevelCompleteWindow.cpp
  17. 62
      Crawler/Menu.cpp
  18. 98
      Crawler/Menu.h
  19. 4
      Crawler/MenuAnimatedIconButton.h
  20. 4
      Crawler/MenuAnimatedIconToggleButton.h
  21. 8
      Crawler/MenuComponent.cpp
  22. 4
      Crawler/MenuComponent.h
  23. 8
      Crawler/MenuIconButton.h
  24. 6
      Crawler/MenuItemButton.h
  25. 8
      Crawler/MenuItemItemButton.h
  26. 4
      Crawler/MenuLabel.h
  27. 27
      Crawler/OverworldMapLevelWindow.cpp
  28. 24
      Crawler/OverworldMenuWindow.cpp
  29. 8
      Crawler/PopupMenuLabel.h
  30. 24
      Crawler/ScrollableWindowComponent.h
  31. 4
      Crawler/SpawnEncounterLabel.h
  32. 4
      Crawler/StatLabel.h
  33. 104
      Crawler/TestSubMenu.cpp
  34. 2
      Crawler/Version.h

@ -1,3 +1,6 @@
The inspiration that started it all, Pokemon-based Nico Yazawa sprite:
https://www.deviantart.com/kirbysmith/art/Nico-Yazawa-Love-Live-Pokemon-Sprites-548007023
*** Minifantasy - Tiny Overworld v1.0 *** *** Minifantasy - Tiny Overworld v1.0 ***
Minifantasy is an original idea by Krishna Palacio Minifantasy is an original idea by Krishna Palacio

@ -50,8 +50,8 @@ INCLUDE_GFX
class CharacterAbilityPreviewComponent:public MenuLabel{ class CharacterAbilityPreviewComponent:public MenuLabel{
Ability*ability; Ability*ability;
public: public:
inline CharacterAbilityPreviewComponent(MenuType parent,geom2d::rect<float>rect,Ability*ability) inline CharacterAbilityPreviewComponent(geom2d::rect<float>rect,Ability*ability)
:MenuLabel(parent,rect,"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND),ability(ability){} :MenuLabel(rect,"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND),ability(ability){}
protected: protected:
virtual void inline Update(Crawler*game)override{ virtual void inline Update(Crawler*game)override{
MenuLabel::Update(game); MenuLabel::Update(game);

@ -53,39 +53,23 @@ void Menu::InitializeClassInfoWindow(){
Menu*classSelectionWindow=Menu::menus[CLASS_SELECTION]; Menu*classSelectionWindow=Menu::menus[CLASS_SELECTION];
ClassInfo data=classutils::GetClassInfo(classSelectionWindow->S(A::CLASS_SELECTION)); ClassInfo data=classutils::GetClassInfo(classSelectionWindow->S(A::CLASS_SELECTION));
MenuLabel*label=NEW MenuLabel(CLASS_INFO,{{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND); auto label=classInfoWindow->ADD("Class Name",MenuLabel)({{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
classInfoWindow->AddComponent("Class Name",label); classInfoWindow->ADD("Rotating Character Display",CharacterRotatingDisplay)({{15,48},{72,120}},GFX[data.classFullImgName].Decal())END;
CharacterRotatingDisplay*classDisplay=NEW CharacterRotatingDisplay(CLASS_INFO,{{15,48},{72,120}},GFX[data.classFullImgName].Decal());
classInfoWindow->AddComponent("Rotating Character Display",classDisplay);
vf2d healthDisplayLabelPos={classInfoWindow->size.x/3,label->GetPos().y+24}; vf2d healthDisplayLabelPos={classInfoWindow->size.x/3,label->GetPos().y+24};
vf2d labelSize={2*classInfoWindow->size.x/3-1,16}; vf2d labelSize={2*classInfoWindow->size.x/3-1,16};
MenuLabel*baseStatsLabel=NEW MenuLabel(CLASS_INFO,{{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE); classInfoWindow->ADD("Base Stats Text",MenuLabel)({{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
classInfoWindow->ADD("Health Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
MenuLabel*healthDisplayLabel=NEW MenuLabel(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE); classInfoWindow->ADD("Attack Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
MenuLabel*atkDisplayLabel=NEW MenuLabel(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE);
classInfoWindow->AddComponent("Base Stats Text",baseStatsLabel);
classInfoWindow->AddComponent("Health Display Text",healthDisplayLabel);
classInfoWindow->AddComponent("Attack Display Text",atkDisplayLabel);
vf2d abilityIconOffsets = {0,32}; vf2d abilityIconOffsets = {0,32};
CharacterAbilityPreviewComponent*ability1=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1); classInfoWindow->ADD("Ability 1 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1)END;
CharacterAbilityPreviewComponent*ability2=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2); classInfoWindow->ADD("Ability 2 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2)END;
CharacterAbilityPreviewComponent*ability3=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3); classInfoWindow->ADD("Ability 3 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3)END;
CharacterAbilityPreviewComponent*rightClickAbility=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility); classInfoWindow->ADD("Right Click Ability Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility)END;
classInfoWindow->AddComponent("Ability 1 Display",ability1);
classInfoWindow->AddComponent("Ability 2 Display",ability2);
classInfoWindow->AddComponent("Ability 3 Display",ability3);
classInfoWindow->AddComponent("Right Click Ability Display",rightClickAbility);
MenuComponent*backButton=NEW MenuComponent(CLASS_INFO,{{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;});
classInfoWindow->AddComponent("Back Button",backButton); classInfoWindow->ADD("Back Button",MenuComponent)({{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
} }

@ -56,15 +56,10 @@ void Menu::InitializeCharacterMenuWindow(){
vf2d windowSize=game->GetScreenSize()-vf2d{52,52}; vf2d windowSize=game->GetScreenSize()-vf2d{52,52};
Menu*characterMenuWindow=CreateMenu(CHARACTER_MENU,CENTERED,windowSize); Menu*characterMenuWindow=CreateMenu(CHARACTER_MENU,CENTERED,windowSize);
MenuLabel*characterLabel=NEW MenuLabel(CHARACTER_MENU,{{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND); characterMenuWindow->ADD("Character Label",MenuLabel)({{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END
characterLabel->decal=true; ->decal=true;
characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)({{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
MenuComponent*equipSlotOutline=NEW MenuComponent(CHARACTER_MENU,{{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE); characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)({{135,28},{90,windowSize.y-37}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END;
CharacterRotatingDisplay*charDisplay=NEW CharacterRotatingDisplay(CHARACTER_MENU,{{135,28},{90,windowSize.y-37}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal());
characterMenuWindow->AddComponent("Character Label",characterLabel);
characterMenuWindow->AddComponent("Equip Slot Outline",equipSlotOutline);
characterMenuWindow->AddComponent("Character Rotating Display",charDisplay);
const static std::array<ItemAttribute,7>displayAttrs{ const static std::array<ItemAttribute,7>displayAttrs{
ItemAttribute::health, ItemAttribute::health,
@ -76,33 +71,31 @@ void Menu::InitializeCharacterMenuWindow(){
ItemAttribute::critDmgPct, ItemAttribute::critDmgPct,
}; };
MenuComponent*equipSelectionOutline=NEW MenuComponent(CHARACTER_MENU,{{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
ScrollableWindowComponent*equipmentList=NEW ScrollableWindowComponent(CHARACTER_MENU,{{123,28},{120,windowSize.y-37-24}});
MenuComponent*equipSelectionBottomOutline=NEW MenuComponent(CHARACTER_MENU,{{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuComponent*equipSelectionSelectButton=NEW MenuComponent(CHARACTER_MENU,{{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select",[](MenuFuncData data){
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(false);
Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(false);
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
}
equipmentWindowOpened=false;
return true;
});
equipSelectionSelectButton->decal=true;
equipSelectionOutline->Enable(false); characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)({{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
equipmentList->Enable(false); ->Enable(false);
equipSelectionBottomOutline->Enable(false); characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)({{123,28},{120,windowSize.y-37-24}})DEPTH -1 END
equipSelectionSelectButton->Enable(false); ->Enable(false);
characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)({{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
->Enable(false);
auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)({{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select",
[](MenuFuncData data){
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(false);
Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(false);
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
}
equipmentWindowOpened=false;
return true;
})END;
characterMenuWindow->AddComponent("Equip Selection Outline",equipSelectionOutline);
characterMenuWindow->AddComponent("Equip List",equipmentList,-1); equipSelectionSelectButton->decal=true;
characterMenuWindow->AddComponent("Equip Selection Bottom Outline",equipSelectionBottomOutline); equipSelectionSelectButton->Enable(false);
characterMenuWindow->AddComponent("Equip Selection Select Button",equipSelectionSelectButton);
const static auto GetLabelText=[](ItemAttribute attribute){ const static auto GetLabelText=[](ItemAttribute attribute){
AttributeData data=ItemAttributable::GetDisplayInfo(attribute); AttributeData data=ItemAttributable::GetDisplayInfo(attribute);
@ -126,139 +119,128 @@ void Menu::InitializeCharacterMenuWindow(){
} }
const static std::array<std::string,8>slotNames{"Helmet","Weapon","Armor","Gloves","Pants","Shoes","Ring 1","Ring 2"}; const static std::array<std::string,8>slotNames{"Helmet","Weapon","Armor","Gloves","Pants","Shoes","Ring 1","Ring 2"};
EquipSlot slot=EquipSlot(equipSlot); EquipSlot slot=EquipSlot(equipSlot);
auto equipmentSlot=characterMenuWindow->ADD("Equip Slot "+slotNames[i],EquipSlotButton)({{x,y+28},{24,24}},slot,MenuType::ENUM_END,
EquipSlotButton*equipmentSlot=NEW EquipSlotButton(CHARACTER_MENU,{{x,y+28},{24,24}},slot,MenuType::ENUM_END, [&](MenuFuncData data){
[&](MenuFuncData data){ EquipSlot slot=EquipSlot(data.component->I(Attribute::EQUIP_TYPE));
EquipSlot slot=EquipSlot(data.component->I(Attribute::EQUIP_TYPE));
std::vector<Item>&equips=Inventory::get("Equipment");
std::vector<Item>&equips=Inventory::get("Equipment"); std::vector<Item>&accessories=Inventory::get("Accessories");
std::vector<Item>&accessories=Inventory::get("Accessories"); std::vector<Item>availableEquipment;
std::vector<Item>availableEquipment; std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](Item&it){
std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](Item&it){ return it.GetEquipSlot()&slot;
return it.GetEquipSlot()&slot; });
}); std::copy_if(accessories.begin(),accessories.end(),std::back_inserter(availableEquipment),[&](Item&it){
std::copy_if(accessories.begin(),accessories.end(),std::back_inserter(availableEquipment),[&](Item&it){ return it.GetEquipSlot()&slot;
return it.GetEquipSlot()&slot; });
});
ScrollableWindowComponent*equipList=Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List");
ScrollableWindowComponent*equipList=Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List"); equipList->RemoveAllComponents();
equipList->RemoveAllComponents(); for(int counter=0;Item&it:availableEquipment){
for(int counter=0;Item&it:availableEquipment){ float xOffset=(counter%3)*26;
float xOffset=(counter%3)*26; Item&itemInvRef=Inventory::GetItem(it.Name());
Item&itemInvRef=Inventory::GetItem(it.Name()); auto equip=equipList->ADD("Equip Item "+std::to_string(counter),MenuItemItemButton)({{2+xOffset,2},{24,24}},itemInvRef,MenuType::ENUM_END,
MenuItemItemButton*equip=NEW MenuItemItemButton(CHARACTER_MENU,{{2+xOffset,2},{24,24}},itemInvRef,MenuType::ENUM_END,[](MenuFuncData data){ [](MenuFuncData data){
MenuItemItemButton*comp=(MenuItemItemButton*)data.component; MenuItemItemButton*comp=(MenuItemItemButton*)data.component;
Inventory::EquipItem(comp->GetItem(),EquipSlot(comp->I(Attribute::EQUIP_TYPE))); Inventory::EquipItem(comp->GetItem(),EquipSlot(comp->I(Attribute::EQUIP_TYPE)));
for(MenuComponent*button:((ScrollableWindowComponent*)data.parentComponent)->GetComponents()){ for(MenuComponent*button:((ScrollableWindowComponent*)data.parentComponent)->GetComponents()){
MenuItemItemButton*comp=(MenuItemItemButton*)button; MenuItemItemButton*comp=(MenuItemItemButton*)button;
comp->SetSelected(false); comp->SetSelected(false);
} }
comp->SetSelected(true); comp->SetSelected(true);
for(int counter=0;ItemAttribute attribute:displayAttrs){ for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label"); StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0); statDisplayLabel->SetStatChangeAmt(0);
}
MenuItemItemButton*equipButton=Component<MenuItemItemButton>(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent->I(A::INDEXED_THEME)]);
equipButton->SetItem(comp->GetItem());
return true;
},[&](MenuFuncData data){
MenuItemItemButton*button=(MenuItemItemButton*)data.component;
Item&buttonItem=button->GetItem();
std::vector<int>statsBeforeEquip;
EquipSlot slot=EquipSlot(button->I(Attribute::EQUIP_TYPE));
for(ItemAttribute attribute:displayAttrs){
statsBeforeEquip.push_back(game->GetPlayer()->GetStat(attribute));
}
Item*equippedItem=Inventory::GetEquip(slot);
Inventory::EquipItem(buttonItem,slot);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
int statChangeAmt=game->GetPlayer()->GetStat(attribute)-statsBeforeEquip[counter];
statDisplayLabel->SetStatChangeAmt(statChangeAmt);
counter++;
}
Inventory::UnequipItem(slot);
if(*equippedItem!=Item::BLANK){
Inventory::EquipItem(*equippedItem,slot);
}
return true;
},[](MenuFuncData data){
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
counter++;
}
return true;
},"Item Name","Item Description")END;
equip->I(Attribute::EQUIP_TYPE)=int(slot);
if(Inventory::GetEquip(slot)==&itemInvRef){
equip->SetSelected(true);
} }
MenuItemItemButton*equipButton=Component<MenuItemItemButton>(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent->I(A::INDEXED_THEME)]); equip->SetCompactDescriptions(false);
equipButton->SetItem(comp->GetItem());
return true; counter++;
},[&](MenuFuncData data){
MenuItemItemButton*button=(MenuItemItemButton*)data.component;
Item&buttonItem=button->GetItem();
std::vector<int>statsBeforeEquip;
EquipSlot slot=EquipSlot(button->I(Attribute::EQUIP_TYPE));
for(ItemAttribute attribute:displayAttrs){
statsBeforeEquip.push_back(game->GetPlayer()->GetStat(attribute));
}
Item*equippedItem=Inventory::GetEquip(slot);
Inventory::EquipItem(buttonItem,slot);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
int statChangeAmt=game->GetPlayer()->GetStat(attribute)-statsBeforeEquip[counter];
statDisplayLabel->SetStatChangeAmt(statChangeAmt);
counter++;
}
Inventory::UnequipItem(slot);
if(*equippedItem!=Item::BLANK){
Inventory::EquipItem(*equippedItem,slot);
}
return true;
},[](MenuFuncData data){
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
counter++;
}
return true;
},"Item Name","Item Description");
equip->I(Attribute::EQUIP_TYPE)=int(slot);
if(Inventory::GetEquip(slot)==&itemInvRef){
equip->SetSelected(true);
} }
equip->SetCompactDescriptions(false); equipList->I(Attribute::INDEXED_THEME)=data.component->I(Attribute::INDEXED_THEME);
equipList->AddComponent(Menu::menus[CHARACTER_MENU],"Equip Item "+std::to_string(counter),equip); Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(true);
counter++; equipList->Enable(true);
} Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(true);
equipList->I(Attribute::INDEXED_THEME)=data.component->I(Attribute::INDEXED_THEME); Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(true);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(true);
equipList->Enable(true);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(true);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(true);
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(false);
equipmentWindowOpened=true;
return true;
},[](MenuFuncData data){//On Mouse Hover
if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""){
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(false); Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(false);
} equipmentWindowOpened=true;
return true; return true;
},[](MenuFuncData data){//On Mouse Out },[](MenuFuncData data){//On Mouse Hover
if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""&&!equipmentWindowOpened){ if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""){
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true); Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(false);
} }
return true; return true;
},"Item Equip Name","Item Equip Description"); },[](MenuFuncData data){//On Mouse Out
PopupMenuLabel*equipmentLabel=NEW PopupMenuLabel(CHARACTER_MENU,{{labelX,labelY},{29,16}},slotNames[i],{0.5,1},ComponentAttr::SHADOW); if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""&&!equipmentWindowOpened){
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true);
}
return true;
},"Item Equip Name","Item Equip Description")END;
equipmentSlot->I(Attribute::EQUIP_TYPE)=int(slot); equipmentSlot->I(Attribute::EQUIP_TYPE)=int(slot);
equipmentSlot->I(Attribute::INDEXED_THEME)=i; equipmentSlot->I(Attribute::INDEXED_THEME)=i;
equipmentSlot->SetShowQuantity(false); equipmentSlot->SetShowQuantity(false);
equipmentSlot->SetCompactDescriptions(false); equipmentSlot->SetCompactDescriptions(false);
equipSlot<<=1; equipSlot<<=1;
characterMenuWindow->AddComponent("Equip Slot "+slotNames[i],equipmentSlot); characterMenuWindow->ADD("Equip Label "+slotNames[i],PopupMenuLabel)({{labelX,labelY},{29,16}},slotNames[i],{0.5,1},ComponentAttr::SHADOW)END;
characterMenuWindow->AddComponent("Equip Label "+slotNames[i],equipmentLabel);
Menu::AddEquipStatListener(equipmentSlot); Menu::AddEquipStatListener(equipmentSlot);
} }
MenuComponent*statDisplayOutline=NEW MenuComponent(CHARACTER_MENU,{{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE); characterMenuWindow->ADD("Stat Display Outline",MenuComponent)({{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
characterMenuWindow->AddComponent("Stat Display Outline",statDisplayOutline);
int yOffset=0; int yOffset=0;
for(ItemAttribute attribute:displayAttrs){ for(ItemAttribute attribute:displayAttrs){
std::string attrStr=GetLabelText(attribute); std::string attrStr=GetLabelText(attribute);
StatLabel*attrLabel=NEW StatLabel(CHARACTER_MENU,{{245,28+2+float(yOffset)},{62,18}},attribute,1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
yOffset+=20;
AttributeData data=ItemAttributable::GetDisplayInfo(attribute); AttributeData data=ItemAttributable::GetDisplayInfo(attribute);
characterMenuWindow->AddComponent("Attribute "+data.name+" Label",attrLabel); auto attrLabel=characterMenuWindow->ADD("Attribute "+data.name+" Label",StatLabel)({{245,28+2+float(yOffset)},{62,18}},attribute,1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
Menu::AddEquipStatListener(attrLabel); Menu::AddEquipStatListener(attrLabel);
yOffset+=20;
} }
MenuComponent*backButton=NEW MenuComponent(CHARACTER_MENU,{{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;}); characterMenuWindow->ADD("Back button",MenuComponent)({{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END
backButton->decal=true; ->decal=true;
characterMenuWindow->AddComponent("Back button",backButton);
MenuLabel*itemNameDisplay=NEW MenuLabel(CHARACTER_MENU,{{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW); auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)({{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
MenuLabel*itemDescriptionDisplay=NEW MenuLabel(CHARACTER_MENU,{{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW); auto itemDescriptionDisplay=characterMenuWindow->ADD("Item Description",MenuLabel)({{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
characterMenuWindow->ADD("Item Equip Name",MenuLabel)({{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
itemNameDisplay->decal=true; characterMenuWindow->ADD("Item Equip Description",MenuLabel)({{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
itemDescriptionDisplay->decal=true;
itemNameDisplay->decal=itemDescriptionDisplay->decal=true;
itemNameDisplay->Enable(false); itemNameDisplay->Enable(false);
itemDescriptionDisplay->Enable(false); itemDescriptionDisplay->Enable(false);
MenuLabel*itemNameDisplayEquip=NEW MenuLabel(CHARACTER_MENU,{{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW);
MenuLabel*itemDescriptionDisplayEquip=NEW MenuLabel(CHARACTER_MENU,{{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW);
characterMenuWindow->AddComponent("Item Name",itemNameDisplay);
characterMenuWindow->AddComponent("Item Description",itemDescriptionDisplay);
characterMenuWindow->AddComponent("Item Equip Name",itemNameDisplayEquip);
characterMenuWindow->AddComponent("Item Equip Description",itemDescriptionDisplayEquip);
} }

@ -49,8 +49,8 @@ protected:
float rotatingFactor=7; float rotatingFactor=7;
float perspectiveFactor=6; float perspectiveFactor=6;
public: public:
inline CharacterRotatingDisplay(MenuType parent,geom2d::rect<float>rect,Decal*icon) inline CharacterRotatingDisplay(geom2d::rect<float>rect,Decal*icon)
:MenuComponent(parent,rect,"",DO_NOTHING),icon(icon){} :MenuComponent(rect,"",DO_NOTHING),icon(icon){}
inline void SetIcon(Decal*icon){ inline void SetIcon(Decal*icon){
this->icon=icon; this->icon=icon;
} }

@ -53,25 +53,21 @@ void Menu::InitializeClassSelectionWindow(){
vf2d outlineSize=classSelectionWindow->size-vf2d{13,13}; vf2d outlineSize=classSelectionWindow->size-vf2d{13,13};
MenuLabel*classSelectionLabel=NEW MenuLabel(CLASS_SELECTION,{{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND); classSelectionWindow->ADD("Class Selection Title Label",MenuLabel)({{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
classSelectionWindow->AddComponent("Class Selection Title Label",classSelectionLabel);
MenuLabel*outline=NEW MenuLabel(CLASS_SELECTION,{{4,4},outlineSize},"",1,ComponentAttr::OUTLINE); auto outline=classSelectionWindow->ADD("Outline Border",MenuLabel)({{4,4},outlineSize},"",1,ComponentAttr::OUTLINE)END;
classSelectionWindow->AddComponent("Outline Border",outline);
vf2d navigationButtonSize={24*2.5f,16}; vf2d navigationButtonSize={24*2.5f,16};
MenuComponent*backButton=NEW MenuComponent(CLASS_SELECTION,{{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;}); classSelectionWindow->ADD("Back Button",MenuComponent)({{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
classSelectionWindow->AddComponent("Back Button",backButton);
MenuComponent*confirmButton=NEW MenuComponent(CLASS_SELECTION,{{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){ classSelectionWindow->ADD("Confirm",MenuComponent)({{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){
std::string selectedClass=data.component->S(A::CLASS_SELECTION); std::string selectedClass=data.component->S(A::CLASS_SELECTION);
data.game->ChangePlayerClass(classutils::StringToClass(selectedClass)); data.game->ChangePlayerClass(classutils::StringToClass(selectedClass));
GameState::ChangeState(States::OVERWORLD_MAP); GameState::ChangeState(States::OVERWORLD_MAP);
return true; return true;
}); })END
confirmButton->disabled=true; ->disabled=true;
classSelectionWindow->AddComponent("Confirm",confirmButton);
vf2d buttonPadding={2,2}; vf2d buttonPadding={2,2};
vf2d buttonSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/9-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug. vf2d buttonSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/9-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug.
@ -111,26 +107,27 @@ void Menu::InitializeClassSelectionWindow(){
buttonStartPos.y+(buttonSize.y+buttonPadding.y+2*outlineSize.y/9)*float(i/3), buttonStartPos.y+(buttonSize.y+buttonPadding.y+2*outlineSize.y/9)*float(i/3),
}; };
vf2d backgroundSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/3-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug. vf2d backgroundSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/3-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug.
MenuLabel*backgroundOutline=NEW MenuLabel(CLASS_SELECTION,{backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
MenuLabel*classLabel=NEW MenuLabel(CLASS_SELECTION,{backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW);
MenuAnimatedIconToggleButton*classSprite=NEW MenuAnimatedIconToggleButton(CLASS_SELECTION,{backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){ classSelectionWindow->ADD(className+" Background",MenuLabel)({backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
data.menu.components["Confirm"]->Enable(true); classSelectionWindow->ADD(className+" Button",MenuComponent)({offsetPos,buttonSize},"Info",CLASS_INFO,
data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
return true;
});
toggleGroup.push_back(classSprite);
MenuComponent*classButton=NEW MenuComponent(CLASS_SELECTION,{offsetPos,buttonSize},"Info",CLASS_INFO,
[](MenuFuncData data){ [](MenuFuncData data){
data.menu.S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION); data.menu.S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
delete Menu::menus[CLASS_INFO]; delete Menu::menus[CLASS_INFO];
Menu::InitializeClassInfoWindow(); Menu::InitializeClassInfoWindow();
return true; return true;
}); })END
classSprite->S(A::CLASS_SELECTION)=classButton->S(A::CLASS_SELECTION)=className; ->S(A::CLASS_SELECTION)=className;
classSelectionWindow->AddComponent(className+" Background",backgroundOutline); classSelectionWindow->ADD(className+" Label",MenuLabel)({backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW)END;
classSelectionWindow->AddComponent(className+" Button",classButton); auto classSprite=classSelectionWindow->ADD(className+" Icon",MenuAnimatedIconToggleButton)({backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){
classSelectionWindow->AddComponent(className+" Label",classLabel); data.menu.components["Confirm"]->Enable(true);
classSelectionWindow->AddComponent(className+" Icon",classSprite); data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
return true;
})END;
classSprite->S(A::CLASS_SELECTION)=className;
toggleGroup.push_back(classSprite);
} }
for(IToggleable*item:toggleGroup){ for(IToggleable*item:toggleGroup){

@ -445,7 +445,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
} }
if(GetKey(I).bPressed){ if(GetKey(I).bPressed){
Menu::OpenMenu(INVENTORY); Menu::OpenMenu(INVENTORY_CONSUMABLES);
} }
if(GetKey(O).bPressed){ if(GetKey(O).bPressed){
ItemDrop::SpawnItem(&ITEM_DATA.at("Green Slime Remains"),player->GetPos(),player->OnUpperLevel()); ItemDrop::SpawnItem(&ITEM_DATA.at("Green Slime Remains"),player->GetPos(),player->OnUpperLevel());
@ -1232,8 +1232,8 @@ void Crawler::RenderHud(){
DrawShadowStringDecal({0,128},player->GetPos().str()); DrawShadowStringDecal({0,128},player->GetPos().str());
DrawShadowStringDecal({0,136},"Spd: "+std::to_string(player->GetMoveSpdMult())); DrawShadowStringDecal({0,136},"Spd: "+std::to_string(player->GetMoveSpdMult()));
DrawShadowStringDecal({0,92},"Loadout Slot 1 Qty: "+std::to_string(GetLoadoutItem(0).Amt())); DrawShadowStringDecal({0,92},"Loadout Slot 1 Qty: "+std::to_string(GetLoadoutItem(0).Amt()));
DrawShadowStringDecal({0,1},"Selection: "+Menu::menus[INVENTORY]->selection.str()); DrawShadowStringDecal({0,1},"Selection: "+Menu::menus[INVENTORY_CONSUMABLES]->selection.str());
DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY]->buttonHoldTime)); DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY_CONSUMABLES]->buttonHoldTime));
}} }}
void Crawler::RenderCooldowns(){ void Crawler::RenderCooldowns(){

@ -411,6 +411,10 @@
<ClCompile Include="FireBolt.cpp" /> <ClCompile Include="FireBolt.cpp" />
<ClCompile Include="GameState.cpp" /> <ClCompile Include="GameState.cpp" />
<ClCompile Include="InventoryConsumableWindow.cpp" /> <ClCompile Include="InventoryConsumableWindow.cpp" />
<ClCompile Include="InventoryWindow.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Item.cpp" /> <ClCompile Include="Item.cpp" />
<ClCompile Include="ItemDrop.cpp" /> <ClCompile Include="ItemDrop.cpp" />
<ClCompile Include="ItemLoadoutWindow.cpp" /> <ClCompile Include="ItemLoadoutWindow.cpp" />
@ -450,8 +454,6 @@
<ClCompile Include="State_OverworldMap.cpp" /> <ClCompile Include="State_OverworldMap.cpp" />
<ClCompile Include="State_Story.cpp" /> <ClCompile Include="State_Story.cpp" />
<ClCompile Include="Test.cpp" /> <ClCompile Include="Test.cpp" />
<ClCompile Include="TestMenu.cpp" />
<ClCompile Include="TestSubMenu.cpp" />
<ClCompile Include="Thief.cpp" /> <ClCompile Include="Thief.cpp" />
<ClCompile Include="Trapper.cpp" /> <ClCompile Include="Trapper.cpp" />
<ClCompile Include="Turret.cpp" /> <ClCompile Include="Turret.cpp" />

@ -410,12 +410,6 @@
<ClCompile Include="MenuComponent.cpp"> <ClCompile Include="MenuComponent.cpp">
<Filter>Source Files\Interface</Filter> <Filter>Source Files\Interface</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="TestMenu.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
<ClCompile Include="TestSubMenu.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
<ClCompile Include="State_GameRun.cpp"> <ClCompile Include="State_GameRun.cpp">
<Filter>Source Files\Game States</Filter> <Filter>Source Files\Game States</Filter>
</ClCompile> </ClCompile>
@ -491,6 +485,9 @@
<ClCompile Include="AttributableStat.cpp"> <ClCompile Include="AttributableStat.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="InventoryWindow.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="cpp.hint" /> <None Include="cpp.hint" />

@ -50,8 +50,8 @@ INCLUDE_LEVEL_NAMES
class EncountersSpawnListScrollableWindowComponent:public ScrollableWindowComponent{ class EncountersSpawnListScrollableWindowComponent:public ScrollableWindowComponent{
protected: protected:
public: public:
inline EncountersSpawnListScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE) inline EncountersSpawnListScrollableWindowComponent(geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(parent,rect,attributes){} :ScrollableWindowComponent(rect,attributes){}
virtual inline void UpdateSpawns(std::vector<int>&spawns){ virtual inline void UpdateSpawns(std::vector<int>&spawns){
Menu::menus.at(parentMenu)->components.erase_if([&](auto key){ Menu::menus.at(parentMenu)->components.erase_if([&](auto key){
if(key.first.starts_with("Spawn ")){ if(key.first.starts_with("Spawn ")){
@ -64,8 +64,7 @@ public:
vf2d parentPos=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->pos; vf2d parentPos=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->pos;
vf2d parentSize=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->size; vf2d parentSize=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->size;
for(int spawn:spawns){ for(int spawn:spawns){
SpawnEncounterLabel*spawnLabel=NEW SpawnEncounterLabel(OVERWORLD_LEVEL_SELECT,{vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn-1).GetDisplayName(),spawn-1); ADD("Spawn "+std::to_string(spawn),SpawnEncounterLabel)({vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn-1).GetDisplayName(),spawn-1)END;
AddComponent(Menu::menus.at(OVERWORLD_LEVEL_SELECT),"Spawn "+std::to_string(spawn),spawnLabel);
offsetY+=14; offsetY+=14;
} }
} }

@ -47,8 +47,8 @@ class EquipSlotButton:public MenuItemItemButton{
private: private:
EquipSlot slot; EquipSlot slot;
public: public:
inline EquipSlotButton(MenuType parent,geom2d::rect<float>rect,EquipSlot slot,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="") inline EquipSlotButton(geom2d::rect<float>rect,EquipSlot slot,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="")
:MenuItemItemButton(parent,rect,Item::BLANK,menuDest,onClick,onHover,onMouseOut,itemNameLabelName,itemDescriptionLabelName),slot(slot){} :MenuItemItemButton(rect,Item::BLANK,menuDest,onClick,onHover,onMouseOut,itemNameLabelName,itemDescriptionLabelName),slot(slot){}
inline void OnEquipStatsUpdate()override{ inline void OnEquipStatsUpdate()override{
Item&equip=*Inventory::GetEquip(slot); Item&equip=*Inventory::GetEquip(slot);
if(!equip.IsBlank()){ if(!equip.IsBlank()){

@ -55,11 +55,11 @@ void Menu::InitializeConsumableInventoryWindow(){
vf2d windowSize={float(totalSpacing*invWidth-itemSpacing+2+24),float(totalSpacing*(3+1)-itemSpacing+64)}; //Need space for the button. vf2d windowSize={float(totalSpacing*invWidth-itemSpacing+2+24),float(totalSpacing*(3+1)-itemSpacing+64)}; //Need space for the button.
Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,windowSize); Menu*inventoryWindow=CreateMenu(INVENTORY_CONSUMABLES,CENTERED,windowSize);
inventoryWindow->I(A::LOADOUT_SLOT)=0; inventoryWindow->I(A::LOADOUT_SLOT)=0;
InventoryScrollableWindowComponent*inventory=NEW InventoryScrollableWindowComponent(INVENTORY,{{1,20},{windowSize.x,float(totalSpacing*3-itemSpacing)}},"Consumables","itemName","itemDescription", inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{1,20},{windowSize.x,float(totalSpacing*3-itemSpacing)}},"Consumables","itemName","itemDescription",
[&](MenuFuncData data){ [&](MenuFuncData data){
MenuItemButton*button=(MenuItemButton*)data.component; MenuItemButton*button=(MenuItemButton*)data.component;
data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT)); data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT));
@ -80,21 +80,13 @@ void Menu::InitializeConsumableInventoryWindow(){
button->selected=data.menu.I(A::LOADOUT_SLOT); button->selected=data.menu.I(A::LOADOUT_SLOT);
data.game->SetLoadoutItem(button->selected,button->GetItem().Name()); data.game->SetLoadoutItem(button->selected,button->GetItem().Name());
return true; return true;
}); })END;
inventoryWindow->AddComponent("inventory",inventory);
//We don't have to actually populate the inventory list because now when an item gets added, it will automatically add the correct component in for us. //We don't have to actually populate the inventory list because now when an item gets added, it will automatically add the correct component in for us.
inventoryWindow->ADD("Inventory Type Label",MenuLabel)({{0,0},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
MenuLabel*inventoryTypeLabel=NEW MenuLabel(INVENTORY,{{0,0},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE); inventoryWindow->ADD("itemName",MenuLabel)(geom2d::rect<float>(vf2d{2,float(initialInvHeight*totalSpacing+itemSpacing-16)},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END;
inventoryWindow->AddComponent("Inventory Type Label",inventoryTypeLabel);
MenuLabel*itemNameLabel=NEW MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,float(initialInvHeight*totalSpacing+itemSpacing-16)},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW};
inventoryWindow->AddComponent("itemName",itemNameLabel);
float itemDescriptionLabelY=float(initialInvHeight*totalSpacing+itemSpacing); float itemDescriptionLabelY=float(initialInvHeight*totalSpacing+itemSpacing);
MenuLabel*itemDescriptionLabel=NEW MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,itemDescriptionLabelY},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW}; inventoryWindow->ADD("itemDescription",MenuLabel)(geom2d::rect<float>(vf2d{2,itemDescriptionLabelY},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END;
inventoryWindow->AddComponent("itemDescription",itemDescriptionLabel);
MenuComponent*okButton=NEW MenuComponent(INVENTORY,{{windowSize.x/2-24,itemDescriptionLabelY+56},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;});
inventoryWindow->AddComponent("OK Button",okButton); inventoryWindow->ADD("OK Button",MenuComponent)({{windowSize.x/2-24,itemDescriptionLabelY+56},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
} }

@ -53,8 +53,8 @@ private:
protected: protected:
ITCategory inventoryType; ITCategory inventoryType;
public: public:
inline InventoryScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ITCategory invType,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE) inline InventoryScrollableWindowComponent(geom2d::rect<float>rect,ITCategory invType,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(parent,rect,attributes),inventoryType(invType),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName), :ScrollableWindowComponent(rect,attributes),inventoryType(invType),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),
inventoryButtonClickAction(inventoryButtonClickAction),inventoryButtonsActive(inventoryButtonsActive){ inventoryButtonClickAction(inventoryButtonClickAction),inventoryButtonsActive(inventoryButtonsActive){
Menu::AddInventoryListener(this,invType); Menu::AddInventoryListener(this,invType);
} }
@ -105,8 +105,7 @@ protected:
int buttonSize="ThemeGlobal.InventoryButtonSize"_I; int buttonSize="ThemeGlobal.InventoryButtonSize"_I;
int totalSpacing="ThemeGlobal.InventoryItemSpacing"_I+buttonSize; int totalSpacing="ThemeGlobal.InventoryItemSpacing"_I+buttonSize;
MenuItemButton*button=NEW MenuItemButton{parentMenu,{{float(totalSpacing*x),float(totalSpacing*y)},{float(buttonSize),float(buttonSize)}},Inventory::get(cat),itemIndex,inventoryButtonClickAction,parentMenu,itemNameLabelName,itemDescriptionLabelName,inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE}; ADD("item_"+cat+"_"+std::to_string(itemIndex),MenuItemButton)({{float(totalSpacing*x),float(totalSpacing*y)},{float(buttonSize),float(buttonSize)}},Inventory::get(cat),itemIndex,inventoryButtonClickAction,parentMenu,itemNameLabelName,itemDescriptionLabelName,inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE)END;
AddComponent(Menu::menus[parentMenu],"item_"+cat+"_"+std::to_string(itemIndex),button);
}else }else
if(components.size()>invSize){ //There are empty spots, so let's clean up. if(components.size()>invSize){ //There are empty spots, so let's clean up.
RemoveEmptySlots(); RemoveEmptySlots();

@ -30,35 +30,32 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE. SUCH DAMAGE.
Portions of this software are copyright © 2023 The FreeType Portions of this software are copyright © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved. All rights reserved.
*/ */
#pragma endregion #pragma endregion
#include "Crawler.h" #include "Crawler.h"
#include "MenuComponent.h" #include "DEFINES.h"
#include "Menu.h"
void Menu::InitializeTestMenu(){ #include "MenuLabel.h"
Menu*testMenu=CreateMenu(TEST,CENTERED,{24*8,24*6});
INCLUDE_game
MenuFunc quitWindow=[](MenuFuncData data){ using A=Attribute;
data.menu.stack.clear(); using enum ComponentAttr;
return true; using ButtonAttr::UNSELECTABLE;
}; using ButtonAttr::UNSELECTABLE_VIA_KEYBOARD;
testMenu->AddComponent("Close",NEW MenuComponent(TEST,{{24*1,24*1},{24*2,24*1}},"Close",quitWindow)); struct testStruct{
int val1;
MenuFunc doNothing=[](MenuFuncData data){return true;}; int val2;
int val3;
testMenu->AddComponent("Test",NEW MenuComponent(TEST,{{24*4,24*1},{24*3,24*1}},"Test",doNothing)); testStruct(int val1,int val2,int val3){};
};
MenuFunc HurtPlayer=[](MenuFuncData data){
data.game->GetPlayer()->Hurt(20,data.game->GetPlayer()->OnUpperLevel(),data.game->GetPlayer()->GetZ()); void Menu::InitializeInventoryWindow(){
return true; Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,game->GetScreenSize()-vi2d{52,52});
};
inventoryWindow->ADD("Inventory Label",MenuLabel)({{0,0},{inventoryWindow->size.x-1,24}},"Inventory",2,SHADOW|OUTLINE|BACKGROUND)END;
testMenu->AddComponent("Hurt Player",NEW MenuComponent(TEST,{{24*4,24*3},{24*3,24*1}},"Hurt Player",HurtPlayer)); inventoryWindow->ADD("Inventory Tabs",MenuComponent)({{0,28},{72,inventoryWindow->size.x-44}},"",DO_NOTHING,UNSELECTABLE)END;
testMenu->AddComponent("Open SubMenu",NEW MenuComponent(TEST,{{24*2,24*4.5},{24*4,24*1}},"Open Another\n Menu",TEST_2,doNothing));
} }

@ -51,28 +51,17 @@ void Menu::InitializeItemLoadoutWindow(){
float itemLoadoutWindowWidth=(game->GetScreenSize().x-5.f); float itemLoadoutWindowWidth=(game->GetScreenSize().x-5.f);
MenuLabel*loadoutLabel=NEW MenuLabel(ITEM_LOADOUT,{{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE); itemLoadoutWindow->ADD("Loadout Label",MenuLabel)({{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
itemLoadoutWindow->AddComponent("Loadout Label",loadoutLabel);
float buttonBorderPadding=64; float buttonBorderPadding=64;
MenuItemItemButton*loadoutItem1=NEW MenuItemItemButton(ITEM_LOADOUT,{{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY,[](MenuFuncData data){Menu::menus.at(INVENTORY)->I(A::LOADOUT_SLOT)=0; return true;},"Item Name Label","Item Description"); itemLoadoutWindow->ADD("Loadout Item 1",MenuItemItemButton)({{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=0; return true;},"Item Name Label","Item Description")END;
MenuItemItemButton*loadoutItem2=NEW MenuItemItemButton(ITEM_LOADOUT,{{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY,[](MenuFuncData data){Menu::menus.at(INVENTORY)->I(A::LOADOUT_SLOT)=1;return true;},"Item Name Label","Item Description"); itemLoadoutWindow->ADD("Loadout Item 2",MenuItemItemButton)({{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=1;return true;},"Item Name Label","Item Description")END;
MenuItemItemButton*loadoutItem3=NEW MenuItemItemButton(ITEM_LOADOUT,{{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY,[](MenuFuncData data){Menu::menus.at(INVENTORY)->I(A::LOADOUT_SLOT)=2;return true;},"Item Name Label","Item Description"); itemLoadoutWindow->ADD("Loadout Item 3",MenuItemItemButton)({{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=2;return true;},"Item Name Label","Item Description")END;
//TODO: Make these two do something.
MenuLabel*itemNameLabel=NEW MenuLabel(ITEM_LOADOUT,{{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW);
MenuLabel*itemDescription=NEW MenuLabel(ITEM_LOADOUT,{{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW);
itemLoadoutWindow->AddComponent("Loadout Item 1",loadoutItem1);
itemLoadoutWindow->AddComponent("Loadout Item 2",loadoutItem2);
itemLoadoutWindow->AddComponent("Loadout Item 3",loadoutItem3);
itemLoadoutWindow->AddComponent("Item Name Label",itemNameLabel);
itemLoadoutWindow->AddComponent("Item Description",itemDescription);
MenuComponent*startLevelButton=NEW MenuComponent(ITEM_LOADOUT,{{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;}); itemLoadoutWindow->ADD("Item Name Label",MenuLabel)({{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW)END;
itemLoadoutWindow->ADD("Item Description",MenuLabel)({{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW)END;
itemLoadoutWindow->AddComponent("Start Level Button",startLevelButton);
itemLoadoutWindow->ADD("Start Level Button",MenuComponent)({{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END;
} }

@ -51,49 +51,29 @@ void Menu::InitializeLevelCompleteWindow(){
Menu*levelCompleteWindow=Menu::CreateMenu(LEVEL_COMPLETE,windowSize.pos,windowSize.size); Menu*levelCompleteWindow=Menu::CreateMenu(LEVEL_COMPLETE,windowSize.pos,windowSize.size);
MenuLabel*stageCompleteLabel=NEW MenuLabel(LEVEL_COMPLETE,{{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW); levelCompleteWindow->ADD("Stage Complete Label",MenuLabel)({{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW)END;
levelCompleteWindow->AddComponent("Stage Complete Label",stageCompleteLabel); levelCompleteWindow->ADD("Monster Loot Outline",MenuComponent)({{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
levelCompleteWindow->ADD("Monster Loot Label",MenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)({{0,44},{windowSize.size.x-80.f,60}},"Monster Loot","Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING)END;
MenuComponent*monsterLootOutline=NEW MenuComponent(LEVEL_COMPLETE,{{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE); levelCompleteWindow->ADD("Stage Loot Outline",MenuComponent)({{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
MenuLabel*monsterLootLabel=NEW MenuLabel(LEVEL_COMPLETE,{{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE); levelCompleteWindow->ADD("Stage Loot Label",MenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
InventoryScrollableWindowComponent*monsterLootWindow=NEW InventoryScrollableWindowComponent(LEVEL_COMPLETE,{{0,44},{windowSize.size.x-80.f,60}},"Monster Loot","Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING); levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)({{0,120},{windowSize.size.x-80.f,60}},"Stage Loot","Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING)END;
levelCompleteWindow->AddComponent("Monster Loot Outline",monsterLootOutline);
levelCompleteWindow->AddComponent("Monster Loot Label",monsterLootLabel);
levelCompleteWindow->AddComponent("Monster Loot Window",monsterLootWindow);
MenuComponent*stageLootOutline=NEW MenuComponent(LEVEL_COMPLETE,{{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuLabel*stageLootLabel=NEW MenuLabel(LEVEL_COMPLETE,{{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE);
InventoryScrollableWindowComponent*stageLootWindow=NEW InventoryScrollableWindowComponent(LEVEL_COMPLETE,{{0,120},{windowSize.size.x-80.f,60}},"Stage Loot","Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING);
levelCompleteWindow->AddComponent("Stage Loot Outline",stageLootOutline);
levelCompleteWindow->AddComponent("Stage Loot Label",stageLootLabel);
levelCompleteWindow->AddComponent("Stage Loot Window",stageLootWindow);
auto nextButtonAction=[](MenuFuncData data){ auto nextButtonAction=[](MenuFuncData data){
Unlock::UnlockArea(State_OverworldMap::GetCurrentConnectionPoint().map); Unlock::UnlockArea(State_OverworldMap::GetCurrentConnectionPoint().map);
GameState::ChangeState(States::OVERWORLD_MAP,0.5f); GameState::ChangeState(States::OVERWORLD_MAP,0.5f);
return true; return true;
}; };
MenuComponent*detailsOutline=NEW MenuComponent(LEVEL_COMPLETE,{{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuLabel*detailsExpGain=NEW MenuLabel(LEVEL_COMPLETE,{{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
MenuComponent*nextButton=NEW MenuComponent(LEVEL_COMPLETE,{{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction);
levelCompleteWindow->AddComponent("Level Details Outline",detailsOutline);
levelCompleteWindow->AddComponent("Level EXP Gain Outline",detailsExpGain);
levelCompleteWindow->AddComponent("Next Button",nextButton);
PopupMenuLabel*monsterLootPopupItemName=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
PopupMenuLabel*monsterLootPopupItemDescription=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
levelCompleteWindow->AddComponent("Monster Loot Popup Item Name",monsterLootPopupItemName); levelCompleteWindow->ADD("Level Details Outline",MenuComponent)({{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
levelCompleteWindow->AddComponent("Monster Loot Popup Item Description",monsterLootPopupItemDescription); levelCompleteWindow->ADD("Level EXP Gain Outline",MenuLabel)({{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
levelCompleteWindow->ADD("Next Button",MenuComponent)({{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction)END;
PopupMenuLabel*stageLootPopupItemName=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND); levelCompleteWindow->ADD("Monster Loot Popup Item Name",PopupMenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
PopupMenuLabel*stageLootPopupItemDescription=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND); levelCompleteWindow->ADD("Monster Loot Popup Item Description",PopupMenuLabel)({{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
levelCompleteWindow->AddComponent("Stage Loot Popup Item Name",stageLootPopupItemName); levelCompleteWindow->ADD("Stage Loot Popup Item Name",PopupMenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
levelCompleteWindow->AddComponent("Stage Loot Popup Item Description",stageLootPopupItemDescription); levelCompleteWindow->ADD("Stage Loot Popup Item Description",PopupMenuLabel)({{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
} }

@ -86,9 +86,8 @@ Menu::~Menu(){
} }
void Menu::InitializeMenus(){ void Menu::InitializeMenus(){
stack.reserve(32); #define MAX_MENUS 32
InitializeTestMenu(); stack.reserve(MAX_MENUS);
InitializeTestSubMenu();
InitializeConsumableInventoryWindow(); InitializeConsumableInventoryWindow();
InitializeClassSelectionWindow(); InitializeClassSelectionWindow();
InitializeClassInfoWindow(); InitializeClassInfoWindow();
@ -98,8 +97,9 @@ void Menu::InitializeMenus(){
InitializeLevelCompleteWindow(); InitializeLevelCompleteWindow();
InitializeOverworldMenuWindow(); InitializeOverworldMenuWindow();
InitializeCharacterMenuWindow(); InitializeCharacterMenuWindow();
InitializeInventoryWindow();
for(MenuType type=TEST;type<MenuType::ENUM_END;type=MenuType(int(type+1))){ for(MenuType type=MenuType(int(MenuType::ENUM_START)+1);type<MenuType::ENUM_END;type=MenuType(int(type+1))){
if(menus.count(type)==0){ if(menus.count(type)==0){
ERR("WARNING! Menu Type "<<type<<" does not exist!") ERR("WARNING! Menu Type "<<type<<" does not exist!")
} }
@ -110,6 +110,7 @@ void Menu::InitializeMenus(){
MenuComponent*component=value; MenuComponent*component=value;
component->AfterCreate(); component->AfterCreate();
} }
if(menus.size()>MAX_MENUS)ERR("WARNING! Exceeded maximum expected menu count of "<<MAX_MENUS<<"!");
} }
if(Menu::unhandledComponents.size()>0){ if(Menu::unhandledComponents.size()>0){
@ -128,62 +129,11 @@ void Menu::InitializeMenus(){
Menu*Menu::CreateMenu(MenuType type,vf2d pos,vf2d size){ Menu*Menu::CreateMenu(MenuType type,vf2d pos,vf2d size){
menus[type]=NEW Menu(pos,size); menus[type]=NEW Menu(pos,size);
menus[type]->type=type;
lastMenuTypeCreated=type; lastMenuTypeCreated=type;
return menus.at(type); return menus.at(type);
} }
void Menu::AddComponent(std::string key,MenuComponent*button,int depth){
if(depth==DEFAULT_DEPTH){
button->depth=STARTING_DEPTH-componentCount;
}else{
button->depth=depth;
}
if(button->selectable){
buttons.Unlock();
if(buttons.count(int(button->rect.pos.y))){
buttons.at(int(button->rect.pos.y)).push_back(button);
}else{
buttons[int(button->rect.pos.y)].push_back(button);
}
if(button->selectableViaKeyboard){
keyboardButtons.Unlock();
if(keyboardButtons.count(int(button->rect.pos.y))){
keyboardButtons.at(int(button->rect.pos.y)).push_back(button);
}else{
keyboardButtons[int(button->rect.pos.y)].push_back(button);
}
}
//We must lock the values before calling sort. Sort seems to try and create new accesses.
buttons.SetInitialized();
keyboardButtons.SetInitialized();
//We make an assumption that menu components are supposed to be in left-to-right order. Sometimes we may add things out-of-order, so this fixes the problem by sorting the items afterwards.
std::sort(buttons[int(button->rect.pos.y)].begin(),buttons[int(button->rect.pos.y)].end(),[](MenuComponent*c1,MenuComponent*c2){
return c1->GetPos().x<c2->GetPos().x;
});
if(keyboardButtons.count(int(button->rect.pos.y))){ //Keyboard buttons may not necessarily contain this key...Let's be sure.
std::sort(keyboardButtons[int(button->rect.pos.y)].begin(),keyboardButtons[int(button->rect.pos.y)].end(),[](MenuComponent*c1,MenuComponent*c2){
return c1->GetPos().x<c2->GetPos().x;
});
}
}else{
displayComponents.push_back(button);
}
RecalculateComponentCount();
if(components.count(key)){
ERR("WARNING! Key "<<key<<" for this sub-menu already exists! Key names must be unique!")
}
button->name=key;
components.Unlock(); //It's possible we can add a component later on, so we will make sure we remove the lock first.
components[key]=button;
components.SetInitialized();
lastRegisteredComponent=key;
std::erase_if(Menu::unhandledComponents,[&](MenuComponent*b1){return b1==button;});
}
void Menu::CheckClickAndPerformMenuSelect(Crawler*game){ void Menu::CheckClickAndPerformMenuSelect(Crawler*game){
if(game->GetMouse(Mouse::LEFT).bReleased||game->GetKey(SPACE).bReleased||game->GetKey(ENTER).bReleased){ if(game->GetMouse(Mouse::LEFT).bReleased||game->GetKey(SPACE).bReleased||game->GetKey(ENTER).bReleased){
MenuSelect(game); MenuSelect(game);

@ -47,13 +47,21 @@ class Crawler;
class MenuComponent; class MenuComponent;
class ScrollableWindowComponent; class ScrollableWindowComponent;
//Add a component to a menu using this macro. Follow-up with END at the end of it.
#define ADD(key,componentType) AddComponent<componentType>(key,NEW componentType
#define END )
#define DEPTH ,
#define DEFAULT_DEPTH -999999 #define DEFAULT_DEPTH -999999
#define STARTING_DEPTH 999999 #define STARTING_DEPTH 999999
enum MenuType{ enum MenuType{
TEST, #pragma region Enum Start //DO NOT REMOVE
TEST_2, ///////////////////////////////////////////////////////////
INVENTORY, /*DO NOT REMOVE!!*/ENUM_START,///////////////////////////////
///////////////////////////////////////////////////////////
#pragma endregion
INVENTORY_CONSUMABLES,
CLASS_INFO, CLASS_INFO,
CLASS_SELECTION, CLASS_SELECTION,
MAIN_MENU, MAIN_MENU,
@ -62,12 +70,26 @@ enum MenuType{
LEVEL_COMPLETE, LEVEL_COMPLETE,
OVERWORLD_MENU, OVERWORLD_MENU,
CHARACTER_MENU, CHARACTER_MENU,
INVENTORY,
#pragma region Enum End //DO NOT REMOVE
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_END//////////////////////////////// /*DO NOT REMOVE!!*/ENUM_END////////////////////////////////
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
#pragma endregion
}; };
class Menu:public IAttributable{ class Menu:public IAttributable{
static void InitializeConsumableInventoryWindow();
static void InitializeClassInfoWindow();
static void InitializeClassSelectionWindow();
static void InitializeMainMenuWindow();
static void InitializeOverworldMapLevelWindow();
static void InitializeItemLoadoutWindow();
static void InitializeLevelCompleteWindow();
static void InitializeOverworldMenuWindow();
static void InitializeCharacterMenuWindow();
static void InitializeInventoryWindow();
friend class Crawler; friend class Crawler;
friend struct Player; friend struct Player;
friend class ItemInfo; friend class ItemInfo;
@ -86,7 +108,62 @@ public:
//The constructor is private. Use CreateMenu() instead! //The constructor is private. Use CreateMenu() instead!
Menu()=default; Menu()=default;
~Menu(); ~Menu();
void AddComponent(std::string key,MenuComponent*button,int depth=DEFAULT_DEPTH); //DO NOT USE DIRECTLY! You should be utilizing the ADD macro for adding components.
template<class T>
T*AddComponent(std::string componentKey,T*component,int depth=DEFAULT_DEPTH){
component->parentMenu=type;
if(depth==DEFAULT_DEPTH){
component->depth=STARTING_DEPTH-componentCount;
}else{
component->depth=depth;
}
if(component->selectable){
buttons.Unlock();
if(buttons.count(int(component->rect.pos.y))){
buttons.at(int(component->rect.pos.y)).push_back(component);
}else{
buttons[int(component->rect.pos.y)].push_back(component);
}
if(component->selectableViaKeyboard){
keyboardButtons.Unlock();
if(keyboardButtons.count(int(component->rect.pos.y))){
keyboardButtons.at(int(component->rect.pos.y)).push_back(component);
}else{
keyboardButtons[int(component->rect.pos.y)].push_back(component);
}
}
//We must lock the values before calling sort. Sort seems to try and create new accesses.
buttons.SetInitialized();
keyboardButtons.SetInitialized();
//We make an assumption that menu components are supposed to be in left-to-right order. Sometimes we may add things out-of-order, so this fixes the problem by sorting the items afterwards.
std::sort(buttons[int(component->rect.pos.y)].begin(),buttons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){
return c1->GetPos().x<c2->GetPos().x;
});
if(keyboardButtons.count(int(component->rect.pos.y))){ //Keyboard buttons may not necessarily contain this key...Let's be sure.
std::sort(keyboardButtons[int(component->rect.pos.y)].begin(),keyboardButtons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){
return c1->GetPos().x<c2->GetPos().x;
});
}
}else{
displayComponents.push_back(component);
}
RecalculateComponentCount();
if(components.count(componentKey)){
ERR("WARNING! Key "<<componentKey<<" for this sub-menu already exists! Key names must be unique!")
}
component->name=componentKey;
components.Unlock(); //It's possible we can add a component later on, so we will make sure we remove the lock first.
components[componentKey]=component;
components.SetInitialized();
lastRegisteredComponent=componentKey;
std::erase_if(Menu::unhandledComponents,[&](auto b1){return b1==component;});
return component;
}
void Update(Crawler*game); void Update(Crawler*game);
void Draw(Crawler*game); void Draw(Crawler*game);
static void InitializeMenus(); static void InitializeMenus();
@ -133,18 +210,6 @@ private:
void CheckClickAndPerformMenuSelect(Crawler*game); void CheckClickAndPerformMenuSelect(Crawler*game);
//Mandatory before any menu operations! This creates and sets up the menu in memory. //Mandatory before any menu operations! This creates and sets up the menu in memory.
static Menu*CreateMenu(MenuType type,vf2d pos,vf2d size); static Menu*CreateMenu(MenuType type,vf2d pos,vf2d size);
static void InitializeTestMenu();
static void InitializeTestSubMenu();
static void InitializeConsumableInventoryWindow();
static void InitializeClassInfoWindow();
static void InitializeClassSelectionWindow();
static void InitializeMainMenuWindow();
static void InitializeOverworldMapLevelWindow();
static void InitializeItemLoadoutWindow();
static void InitializeLevelCompleteWindow();
static void InitializeOverworldMenuWindow();
static void InitializeCharacterMenuWindow();
void KeyboardButtonNavigation(Crawler*game,vf2d menuPos); void KeyboardButtonNavigation(Crawler*game,vf2d menuPos);
static void DrawScaledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor); static void DrawScaledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor);
@ -156,6 +221,7 @@ private:
bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton); bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton);
Pixel GetRenderColor(); Pixel GetRenderColor();
MenuType type;
static bool MOUSE_NAVIGATION; static bool MOUSE_NAVIGATION;
bool cover; //A black cover for when a menu pops up to fade out the stuff behind it. bool cover; //A black cover for when a menu pops up to fade out the stuff behind it.

@ -48,8 +48,8 @@ protected:
private: private:
float animationTime=0; float animationTime=0;
public: public:
inline MenuAnimatedIconButton(MenuType parent,geom2d::rect<float>rect,std::string animation,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) inline MenuAnimatedIconButton(geom2d::rect<float>rect,std::string animation,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(parent,rect,nullptr,onClick,attributes),animation(animation){} :MenuIconButton(rect,nullptr,onClick,attributes),animation(animation){}
protected: protected:
virtual inline void Update(Crawler*game)override{ virtual inline void Update(Crawler*game)override{
MenuIconButton::Update(game); MenuIconButton::Update(game);

@ -49,8 +49,8 @@ protected:
private: private:
float animationTime=0; float animationTime=0;
public: public:
inline MenuAnimatedIconToggleButton(MenuType parent,geom2d::rect<float>rect,std::string animation,MenuFunc onClick) inline MenuAnimatedIconToggleButton(geom2d::rect<float>rect,std::string animation,MenuFunc onClick)
:MenuAnimatedIconButton(parent,rect,animation,[](MenuFuncData data){ :MenuAnimatedIconButton(rect,animation,[](MenuFuncData data){
MenuAnimatedIconToggleButton*button=(MenuAnimatedIconToggleButton*)data.component; MenuAnimatedIconToggleButton*button=(MenuAnimatedIconToggleButton*)data.component;
button->Select(); button->Select();
button->_onClick(data); button->_onClick(data);

@ -40,13 +40,13 @@ All rights reserved.
using A=Attribute; using A=Attribute;
MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes) MenuComponent::MenuComponent(geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes)
:parentMenu(parent),rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()){ :rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()){
Menu::unhandledComponents.push_back(this); Menu::unhandledComponents.push_back(this);
} }
MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes) MenuComponent::MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes)
:MenuComponent(parent,rect,label,onClick,attributes){ :MenuComponent(rect,label,onClick,attributes){
//NOTE: This constructor also calls the other constructor above! //NOTE: This constructor also calls the other constructor above!
this->menuDest=menuDest; this->menuDest=menuDest;
} }

@ -97,8 +97,8 @@ protected:
public: public:
MenuType parentMenu=MenuType::ENUM_END; MenuType parentMenu=MenuType::ENUM_END;
MenuComponent*parentComponent=nullptr; MenuComponent*parentComponent=nullptr;
MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
virtual ~MenuComponent(); virtual ~MenuComponent();
vf2d GetPos(); vf2d GetPos();
//We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed. //We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed.

@ -51,10 +51,10 @@ class MenuIconButton:public MenuComponent{
protected: protected:
Decal*icon; Decal*icon;
public: public:
inline MenuIconButton(MenuType parent,geom2d::rect<float>rect,Decal*icon,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) inline MenuIconButton(geom2d::rect<float>rect,Decal*icon,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuComponent(parent,rect,"",onClick,ButtonAttr(attributes)),icon(icon){} :MenuComponent(rect,"",onClick,ButtonAttr(attributes)),icon(icon){}
inline MenuIconButton(MenuType parent,geom2d::rect<float>rect,Decal*icon,MenuType menuDest,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) inline MenuIconButton(geom2d::rect<float>rect,Decal*icon,MenuType menuDest,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuComponent(parent,rect,"",menuDest,onClick,ButtonAttr(attributes)),icon(icon){} :MenuComponent(rect,"",menuDest,onClick,ButtonAttr(attributes)),icon(icon){}
protected: protected:
virtual inline void Update(Crawler*game)override{ virtual inline void Update(Crawler*game)override{
MenuComponent::Update(game); MenuComponent::Update(game);

@ -58,8 +58,8 @@ private:
std::string itemDescriptionLabelName; std::string itemDescriptionLabelName;
public: public:
int selected=-1; //0-2 representing which loadout slot this item consumes. -1 means not selected. int selected=-1; //0-2 representing which loadout slot this item consumes. -1 means not selected.
inline MenuItemButton(MenuType parent,geom2d::rect<float>rect,std::vector<Item>&invRef,int invIndex,MenuFunc onClick,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) inline MenuItemButton(geom2d::rect<float>rect,std::vector<Item>&invRef,int invIndex,MenuFunc onClick,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(parent,rect,invRef.size()>invIndex?invRef[invIndex].Decal():nullptr,onClick,attributes),invRef(invRef),inventoryIndex(invIndex),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ :MenuIconButton(rect,invRef.size()>invIndex?invRef[invIndex].Decal():nullptr,onClick,attributes),invRef(invRef),inventoryIndex(invIndex),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){
draggable=false; draggable=false;
valid=invRef.size()>invIndex; valid=invRef.size()>invIndex;
} }
@ -112,7 +112,7 @@ protected:
} }
inline MenuComponent*PickUpDraggableItem()override final{ inline MenuComponent*PickUpDraggableItem()override final{
if(valid){ if(valid){
MenuItemButton*pickUp=NEW MenuItemButton(parentMenu,rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName); MenuItemButton*pickUp=NEW MenuItemButton(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName);
valid=false; valid=false;
return pickUp; return pickUp;
}else{ }else{

@ -62,13 +62,13 @@ private:
bool hideQty=false; bool hideQty=false;
CompactText compact=COMPACT; CompactText compact=COMPACT;
public: public:
inline MenuItemItemButton(MenuType parent,geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName) inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName)
:MenuIconButton(parent,rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(DO_NOTHING){ :MenuIconButton(rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(DO_NOTHING){
draggable=false; draggable=false;
valid=!itemRef.IsBlank(); valid=!itemRef.IsBlank();
} }
inline MenuItemItemButton(MenuType parent,geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="") inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="")
:MenuIconButton(parent,rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(onHover),onMouseOut(onMouseOut){ :MenuIconButton(rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(onHover),onMouseOut(onMouseOut){
runHoverFunctions=true; runHoverFunctions=true;
draggable=false; draggable=false;
valid=!itemRef.IsBlank(); valid=!itemRef.IsBlank();

@ -50,8 +50,8 @@ protected:
bool shadow=false; bool shadow=false;
bool centered=true; bool centered=true;
public: public:
inline MenuLabel(MenuType parent,geom2d::rect<float>rect,std::string label,int scale=1,ComponentAttr attributes=ComponentAttr::NONE) inline MenuLabel(geom2d::rect<float>rect,std::string label,int scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuComponent(parent,rect,label,MenuFunc{},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD),scale(scale),centered(!(attributes&ComponentAttr::LEFT_ALIGN)),shadow(attributes&ComponentAttr::SHADOW){ :MenuComponent(rect,label,MenuFunc{},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD),scale(scale),centered(!(attributes&ComponentAttr::LEFT_ALIGN)),shadow(attributes&ComponentAttr::SHADOW){
border=attributes&ComponentAttr::OUTLINE; border=attributes&ComponentAttr::OUTLINE;
this->background=attributes&ComponentAttr::BACKGROUND; this->background=attributes&ComponentAttr::BACKGROUND;
showDefaultLabel=false; showDefaultLabel=false;

@ -55,25 +55,14 @@ void Menu::InitializeOverworldMapLevelWindow(){
State_OverworldMap*overworldMap=(State_OverworldMap*)GameState::states[States::OVERWORLD_MAP]; //HACK ALERT!! We're going to make an assumption that we are in the overworld map state. State_OverworldMap*overworldMap=(State_OverworldMap*)GameState::states[States::OVERWORLD_MAP]; //HACK ALERT!! We're going to make an assumption that we are in the overworld map state.
MenuLabel*chapterLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN); levelSelectWindow->ADD("Panel 1 Back",MenuLabel)({{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
MenuLabel*stageLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN); levelSelectWindow->ADD("Chapter Label",MenuLabel)({{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
MenuLabel*panel1Back=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE); levelSelectWindow->ADD("Stage Label",MenuLabel)({{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
levelSelectWindow->AddComponent("Panel 1 Back",panel1Back); levelSelectWindow->ADD("Panel 2 Back",MenuLabel)({{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
levelSelectWindow->AddComponent("Chapter Label",chapterLabel); levelSelectWindow->ADD("Encounters Label",MenuLabel)({{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
levelSelectWindow->AddComponent("Stage Label",stageLabel); levelSelectWindow->ADD("Spawns List",EncountersSpawnListScrollableWindowComponent)({{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND)END;
MenuLabel*encountersLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
EncountersSpawnListScrollableWindowComponent*spawns=NEW EncountersSpawnListScrollableWindowComponent(OVERWORLD_LEVEL_SELECT,{{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND);
MenuLabel*panel2Back=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE);
levelSelectWindow->AddComponent("Panel 2 Back",panel2Back);
levelSelectWindow->AddComponent("Encounters Label",encountersLabel);
levelSelectWindow->AddComponent("Spawns List",spawns);
MenuComponent*changeLoadoutButton=NEW MenuComponent(OVERWORLD_LEVEL_SELECT,{{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;});
MenuComponent*enterButton=NEW MenuComponent(OVERWORLD_LEVEL_SELECT,{{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;});
levelSelectWindow->AddComponent("Change Loadout Button",changeLoadoutButton); levelSelectWindow->ADD("Change Loadout Button",MenuComponent)({{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;})END;
levelSelectWindow->AddComponent("Enter Button",enterButton); levelSelectWindow->ADD("Enter Button",MenuComponent)({{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END;
} }

@ -47,18 +47,14 @@ INCLUDE_GFX
void Menu::InitializeOverworldMenuWindow(){ void Menu::InitializeOverworldMenuWindow(){
Menu*overworldMenuWindow=CreateMenu(OVERWORLD_MENU,CENTERED,vi2d{96,164}); Menu*overworldMenuWindow=CreateMenu(OVERWORLD_MENU,CENTERED,vi2d{96,164});
MenuComponent*resumeButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;}); overworldMenuWindow->ADD("Resume Button",MenuComponent)({{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
MenuComponent*characterButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*1},{88,24}},"Character",[](MenuFuncData data){ overworldMenuWindow->ADD("Character Button",MenuComponent)({{4,12+28*1},{88,24}},"Character",
Component<CharacterRotatingDisplay>(CHARACTER_MENU,"Character Rotating Display")->SetIcon(GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal()); [](MenuFuncData data){
Menu::OpenMenu(CHARACTER_MENU); Component<CharacterRotatingDisplay>(CHARACTER_MENU,"Character Rotating Display")->SetIcon(GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal());
return true;}); Menu::OpenMenu(CHARACTER_MENU);
MenuComponent*inventoryButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){/*Menu::OpenMenu(INVENTORY_MENU);*/return true;}); return true;
MenuComponent*settingsButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;}); })END;
MenuComponent*quitButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){game->EndGame();return true;}); overworldMenuWindow->ADD("Inventory Button",MenuComponent)({{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){Menu::OpenMenu(INVENTORY);return true;})END;
overworldMenuWindow->ADD("Settings Button",MenuComponent)({{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;})END;
overworldMenuWindow->AddComponent("Resume Button",resumeButton); overworldMenuWindow->ADD("Quit Button",MenuComponent)({{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){game->EndGame();return true;})END;
overworldMenuWindow->AddComponent("Character Button",characterButton);
overworldMenuWindow->AddComponent("Inventory Button",inventoryButton);
overworldMenuWindow->AddComponent("Settings Button",settingsButton);
overworldMenuWindow->AddComponent("Quit Button",quitButton);
} }

@ -47,11 +47,11 @@ class PopupMenuLabel:public MenuLabel{
private: private:
vf2d scale; vf2d scale;
public: public:
inline PopupMenuLabel(MenuType parent,geom2d::rect<float>rect,std::string label,float scale=1,ComponentAttr attributes=ComponentAttr::NONE) inline PopupMenuLabel(geom2d::rect<float>rect,std::string label,float scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(parent,rect,label,1,attributes),scale({scale,scale}){ :MenuLabel(rect,label,1,attributes),scale({scale,scale}){
} }
inline PopupMenuLabel(MenuType parent,geom2d::rect<float>rect,std::string label,vf2d scale={1,1},ComponentAttr attributes=ComponentAttr::NONE) inline PopupMenuLabel(geom2d::rect<float>rect,std::string label,vf2d scale={1,1},ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(parent,rect,label,1,attributes),scale(scale){ :MenuLabel(rect,label,1,attributes),scale(scale){
} }
protected: protected:
virtual void inline Update(Crawler*game)override{ virtual void inline Update(Crawler*game)override{

@ -59,16 +59,11 @@ protected:
return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET)+vf2d{2,2},component->rect.size-vf2d{2,2}}); return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET)+vf2d{2,2},component->rect.size-vf2d{2,2}});
} }
public: public:
inline ScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE) inline ScrollableWindowComponent(geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:MenuComponent(parent,rect,"",[](MenuFuncData data){return true;},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){ :MenuComponent(rect,"",[](MenuFuncData data){return true;},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
background=attributes&ComponentAttr::BACKGROUND; background=attributes&ComponentAttr::BACKGROUND;
border=attributes&ComponentAttr::OUTLINE; border=attributes&ComponentAttr::OUTLINE;
r.Create(uint32_t(rect.size.x),uint32_t(rect.size.y)); r.Create(uint32_t(rect.size.x),uint32_t(rect.size.y));
upButton=NEW MenuComponent(parentMenu,{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
downButton=NEW MenuComponent(parentMenu,{rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
//Let's use the internal name of this component to add unique names for sub-components.
Menu::menus[parentMenu]->AddComponent(name+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton,-1);
Menu::menus[parentMenu]->AddComponent(name+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton,-1);
} }
virtual inline void RemoveAllComponents(){ virtual inline void RemoveAllComponents(){
while(components.size()>0){ while(components.size()>0){
@ -100,6 +95,11 @@ public:
delete button; delete button;
} }
protected: protected:
virtual inline void AfterCreate()override{
//Let's use the internal name of this component to add unique names for sub-components.
upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH -1 END;
downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH -1 END;
}
virtual inline void BeforeUpdate(Crawler*game)override{ virtual inline void BeforeUpdate(Crawler*game)override{
for(MenuComponent*component:components){ for(MenuComponent*component:components){
component->BeforeUpdate(game); component->BeforeUpdate(game);
@ -229,7 +229,8 @@ protected:
return bounds; return bounds;
} }
public: public:
void inline AddComponent(Menu*parentMenu,std::string key,MenuComponent*button){ template<class T>
T* AddComponent(std::string key,T*button){
components.push_back(button); components.push_back(button);
button->renderInMain=false; //Now we are in control! button->renderInMain=false; //Now we are in control!
button->parentComponent=this; button->parentComponent=this;
@ -253,7 +254,8 @@ public:
bounds.size.y+=sizeIncrease; bounds.size.y+=sizeIncrease;
} }
parentMenu->AddComponent(key,button); Menu::menus[parentMenu]->AddComponent(key,button);
return button;
} }
virtual inline bool PointWithinParent(MenuComponent*child,vi2d drawPos)override{ virtual inline bool PointWithinParent(MenuComponent*child,vi2d drawPos)override{
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawPos); return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawPos);
@ -270,7 +272,7 @@ public:
} }
virtual inline void Enable(bool enabled)override final{ virtual inline void Enable(bool enabled)override final{
disabled=!enabled; disabled=!enabled;
upButton->Enable(enabled); if(upButton){upButton->Enable(enabled);}
downButton->Enable(enabled); if(downButton){downButton->Enable(enabled);}
}; };
}; };

@ -50,8 +50,8 @@ class SpawnEncounterLabel:public MenuLabel{
Animate2D::Animation<std::string>anim; Animate2D::Animation<std::string>anim;
Animate2D::AnimationState state; Animate2D::AnimationState state;
public: public:
inline SpawnEncounterLabel(MenuType parent,geom2d::rect<float>rect,std::string label,int monsterID) inline SpawnEncounterLabel(geom2d::rect<float>rect,std::string label,int monsterID)
:MenuLabel(parent,rect,label),monsterID(monsterID){ :MenuLabel(rect,label),monsterID(monsterID){
anim.AddState("IDLE",ANIMATION_DATA.at(MONSTER_DATA.at(monsterID).GetIdleAnimation())); anim.AddState("IDLE",ANIMATION_DATA.at(MONSTER_DATA.at(monsterID).GetIdleAnimation()));
anim.ChangeState(state,"IDLE"); anim.ChangeState(state,"IDLE");
anim.UpdateState(state,util::random(1)); anim.UpdateState(state,util::random(1));

@ -49,8 +49,8 @@ private:
int value=0; int value=0;
int statChangeAmt=0; int statChangeAmt=0;
public: public:
inline StatLabel(MenuType parent,geom2d::rect<float>rect,ItemAttribute stat,int scale=1,ComponentAttr attributes=ComponentAttr::NONE) inline StatLabel(geom2d::rect<float>rect,ItemAttribute stat,int scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(parent,rect,"",scale,attributes),stat(stat){ :MenuLabel(rect,"",scale,attributes),stat(stat){
border=attributes&ComponentAttr::OUTLINE; border=attributes&ComponentAttr::OUTLINE;
this->background=attributes&ComponentAttr::BACKGROUND; this->background=attributes&ComponentAttr::BACKGROUND;
showDefaultLabel=false; showDefaultLabel=false;

@ -1,104 +0,0 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2018 - 2023 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "Crawler.h"
#include "DEFINES.h"
#include "olcPixelGameEngine.h"
#include "safemap.h"
#include "MenuIconButton.h"
#include "MenuLabel.h"
INCLUDE_GFX
using A=Attribute;
void Menu::InitializeTestSubMenu(){
Menu*testSubMenu=CreateMenu(TEST_2,{30,30},{24*4,24*5});
MenuFunc goBack=[](MenuFuncData data){
data.menu.stack.pop_back();
return true;
};
testSubMenu->AddComponent("BACK",NEW MenuComponent(TEST_2,{{24*1,24*1},{24*2,24*1}},"Go Back",goBack));
int index=0;
for(auto&theme:Menu::themes){
if(theme.displayName==Menu::themeSelection){
testSubMenu->I(A::INDEXED_THEME)=index;
break;
}
index++;
}
MenuFunc themePrev=[](MenuFuncData data){
bool found=false;
data.menu.I(A::INDEXED_THEME)--;
if(data.menu.I(A::INDEXED_THEME)<0){
data.menu.I(A::INDEXED_THEME)=int(themes.size()-1);
}
int index=0;
for(auto&theme:Menu::themes){
if(index==data.menu.I(A::INDEXED_THEME)){
Menu::themeSelection=theme.displayName;
((MenuLabel*)(data.menu.components["THEME_DISPLAY"]))->SetLabel("Theme\n"+Menu::themes[themeSelection].GetThemeName());
break;
}
index++;
}
return true;
};
testSubMenu->AddComponent("PREV_THEME",NEW MenuComponent(TEST_2,{{24*-0.5,24*3},{24*1,24*1}},"<",themePrev));
testSubMenu->AddComponent("THEME_DISPLAY",NEW MenuLabel(TEST_2,{{24*0.5,24*3},{24*3,24*1}},"Theme\n"+Menu::themes[themeSelection].GetThemeName()));
MenuFunc themeNext=[](MenuFuncData data){
data.menu.I(A::INDEXED_THEME)=(size_t(data.menu.I(A::INDEXED_THEME))+1)%themes.size();
int index=0;
for(auto&theme:Menu::themes){
if(index==data.menu.I(A::INDEXED_THEME)){
Menu::themeSelection=theme.displayName;
((MenuLabel*)(data.menu.components["THEME_DISPLAY"]))->SetLabel("Theme\n"+Menu::themes[themeSelection].GetThemeName());
break;
}
index++;
}
return true;
};
testSubMenu->AddComponent("NEXT_THEME",NEW MenuComponent(TEST_2,{{24*3.5,24*3},{24*1,24*1}},">",themeNext));
}

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 1 #define VERSION_PATCH 1
#define VERSION_BUILD 3692 #define VERSION_BUILD 3722
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

Loading…
Cancel
Save