Add player money functions. Implement Merchant transaction functions. Add Function Priming classes.

pull/28/head
sigonasr2 12 months ago
parent 2b3c1ea1b4
commit f1aa872717
  1. 2
      Crawler/CharacterMenuWindow.cpp
  2. 8
      Crawler/Crawler.cpp
  3. 4
      Crawler/Crawler.vcxproj
  4. 3
      Crawler/Crawler.vcxproj.filters
  5. 2
      Crawler/EquipSlotButton.h
  6. 63
      Crawler/FunctionPriming.h
  7. 2
      Crawler/InventoryConsumableWindow.cpp
  8. 111
      Crawler/Item.cpp
  9. 61
      Crawler/Item.h
  10. 4
      Crawler/ItemDrop.cpp
  11. 16
      Crawler/MenuItemButton.h
  12. 10
      Crawler/MenuItemItemButton.h
  13. 96
      Crawler/Merchant.cpp
  14. 20
      Crawler/Merchant.h
  15. 7
      Crawler/Player.cpp
  16. 4
      Crawler/Player.h
  17. 6
      Crawler/RowItemDisplay.h
  18. 2
      Crawler/Version.h
  19. 18
      Crawler/assets/config/shops/Chapter 1 Merchants.txt

@ -134,7 +134,7 @@ void Menu::InitializeCharacterMenuWindow(){
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){
Item&itemInvRef=Inventory::GetItem(it.Name()); Item&itemInvRef=Inventory::GetItem(it.ActualName());
auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)({{2,2+counter*28.f},{120-15,28}},itemInvRef, auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)({{2,2+counter*28.f},{120-15,28}},itemInvRef,
[](MenuFuncData data){ [](MenuFuncData data){
RowItemDisplay*comp=dynamic_cast<RowItemDisplay*>(data.component); RowItemDisplay*comp=dynamic_cast<RowItemDisplay*>(data.component);

@ -203,6 +203,10 @@ bool Crawler::OnUserCreate(){
ValidateGameStatus(); //Checks to make sure everything has been initialized properly. ValidateGameStatus(); //Checks to make sure everything has been initialized properly.
Merchant::RandomizeTravelingMerchant();
Merchant&myMerchant=Merchant::GetCurrentTravelingMerchant();
const std::vector<Item>&itemsAvailable=myMerchant.GetShopItems();
return true; return true;
} }
@ -1725,6 +1729,7 @@ void Crawler::ChangePlayerClass(Class cl){
Ability itemAbility1=player->useItem1; Ability itemAbility1=player->useItem1;
Ability itemAbility2=player->useItem2; Ability itemAbility2=player->useItem2;
Ability itemAbility3=player->useItem3; Ability itemAbility3=player->useItem3;
uint32_t oldMoney=player->money;
switch(cl){ switch(cl){
case WARRIOR:{ case WARRIOR:{
player.reset(NEW Warrior(player.get())); player.reset(NEW Warrior(player.get()));
@ -1750,6 +1755,7 @@ void Crawler::ChangePlayerClass(Class cl){
player->SetBaseStat(ItemAttribute::attack,DATA.GetProperty(player->GetClassName()+".BaseAtk").GetInt()); player->SetBaseStat(ItemAttribute::attack,DATA.GetProperty(player->GetClassName()+".BaseAtk").GetInt());
player->hpGrowthRate=float(DATA.GetProperty(player->GetClassName()+".HealthGrowthRate").GetReal()); player->hpGrowthRate=float(DATA.GetProperty(player->GetClassName()+".HealthGrowthRate").GetReal());
player->atkGrowthRate=float(DATA.GetProperty(player->GetClassName()+".AtkGrowthRate").GetReal()); player->atkGrowthRate=float(DATA.GetProperty(player->GetClassName()+".AtkGrowthRate").GetReal());
player->money=oldMoney;
sig::Animation::SetupPlayerAnimations(); sig::Animation::SetupPlayerAnimations();
GetPlayer()->UpdateIdleAnimation(DOWN); GetPlayer()->UpdateIdleAnimation(DOWN);
GetPlayer()->SetItem1UseFunc(itemAbility1); GetPlayer()->SetItem1UseFunc(itemAbility1);
@ -2239,7 +2245,7 @@ void Crawler::SetLoadoutItem(int slot,std::string itemName){
bool Crawler::UseLoadoutItem(int slot){ bool Crawler::UseLoadoutItem(int slot){
if(slot<0||slot>loadout.size()-1)ERR("Invalid inventory slot "+std::to_string(slot)+", please choose a slot in range (0-"+std::to_string(loadout.size()-1)+")."); if(slot<0||slot>loadout.size()-1)ERR("Invalid inventory slot "+std::to_string(slot)+", please choose a slot in range (0-"+std::to_string(loadout.size()-1)+").");
if(GetLoadoutItem(slot).Amt()>0){ if(GetLoadoutItem(slot).Amt()>0){
Inventory::UseItem(loadout[slot].Name()); Inventory::UseItem(loadout[slot].ActualName());
GetLoadoutItem(slot).OnUseAction(); GetLoadoutItem(slot).OnUseAction();
GetLoadoutItem(slot).amt--; GetLoadoutItem(slot).amt--;
return true; return true;

@ -316,6 +316,10 @@
</SubType> </SubType>
</ClInclude> </ClInclude>
<ClInclude Include="Error.h" /> <ClInclude Include="Error.h" />
<ClInclude Include="FunctionPriming.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="GameState.h" /> <ClInclude Include="GameState.h" />
<ClInclude Include="Item.h" /> <ClInclude Include="Item.h" />
<ClInclude Include="ItemDrop.h"> <ClInclude Include="ItemDrop.h">

@ -309,6 +309,9 @@
<ClInclude Include="Merchant.h"> <ClInclude Include="Merchant.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FunctionPriming.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Player.cpp"> <ClCompile Include="Player.cpp">

@ -52,7 +52,7 @@ public:
inline void OnEquipStatsUpdate()override{ inline void OnEquipStatsUpdate()override{
Item&equip=*Inventory::GetEquip(slot); Item&equip=*Inventory::GetEquip(slot);
if(!equip.IsBlank()){ if(!equip.IsBlank()){
icon=equip.Decal(); icon=const_cast<Decal*>(equip.Decal());
SetItem(equip); SetItem(equip);
}else{ }else{
icon=nullptr; icon=nullptr;

@ -0,0 +1,63 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2018 - 2022 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
#pragma once
#include "Error.h"
#include <format>
using IT=std::string;
struct FunctionPrimingData{
bool primed=false;
std::string dependentFunction="";
inline FunctionPrimingData(std::string dependentFunction)
:dependentFunction(dependentFunction){}
};
struct MerchantFunctionPrimingData:public FunctionPrimingData{
IT item="";
uint32_t amt=0;
inline MerchantFunctionPrimingData(std::string dependentFunction)
:FunctionPrimingData(dependentFunction){}
virtual inline void Validate(IT item,uint32_t amt)const{
if(!primed)ERR(std::format("WARNING! {} should be called before running this function! Priming Requirement!",dependentFunction));
if(this->item!=item)ERR(std::format("WARNING! Primed items are not matching! {}!={}",this->item,item));
if(this->amt!=amt)ERR(std::format("WARNING! Primed amounts are not matching! {}!={}",this->amt,amt));
}
inline bool operator=(bool rhs){
return primed=rhs;
}
};

@ -75,7 +75,7 @@ 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().ActualName());
return true; return true;
})END; })END;

@ -102,6 +102,8 @@ void ItemInfo::InitializeItems(){
std::vector<std::string> slot; std::vector<std::string> slot;
float cooldownTime="Item.Item Cooldown Time"_F; float cooldownTime="Item.Item Cooldown Time"_F;
std::vector<ItemAttribute>statValueList; std::vector<ItemAttribute>statValueList;
uint32_t sellValue=0;
uint32_t buyValue=0;
for(auto&[itemKey,itemValue]:data[key].GetKeys()){ for(auto&[itemKey,itemValue]:data[key].GetKeys()){
std::string keyName=itemKey; std::string keyName=itemKey;
if(keyName=="Description"){ if(keyName=="Description"){
@ -131,6 +133,12 @@ void ItemInfo::InitializeItems(){
}else }else
if(keyName=="PartofSet"){ if(keyName=="PartofSet"){
setName=data[key][keyName].GetString(); setName=data[key][keyName].GetString();
}
if(keyName=="BuyValue"){
buyValue=data[key][keyName].GetInt();
}else
if(keyName=="SellValue"){
sellValue=data[key][keyName].GetInt();
}else{ //THis is a custom override modifier for a script. NO-OP }else{ //THis is a custom override modifier for a script. NO-OP
} }
} }
@ -162,6 +170,8 @@ void ItemInfo::InitializeItems(){
it.cooldownTime=cooldownTime; it.cooldownTime=cooldownTime;
it.slot=EquipSlot::NONE; it.slot=EquipSlot::NONE;
it.set=setName; it.set=setName;
it.buyValue=buyValue;
it.sellValue=sellValue;
if(slot.size()>0){ if(slot.size()>0){
for(std::string&s:slot){ for(std::string&s:slot){
if(!nameToEquipSlot.count(s))ERR("WARNING! Tried to add item "<<it.name<<" to slot "<<s<<" which doesn't exist!"); if(!nameToEquipSlot.count(s))ERR("WARNING! Tried to add item "<<it.name<<" to slot "<<s<<" which doesn't exist!");
@ -294,7 +304,7 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){
} }
int count=0; int count=0;
for(Item&item:inv){ for(Item&item:inv){
if(item.Name()==it)break; if(item==it)break;
count++; count++;
} }
#pragma endregion #pragma endregion
@ -376,27 +386,31 @@ bool Inventory::SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2)
return true; return true;
} }
uint32_t Item::Amt(){ uint32_t Item::Amt()const{
return amt; return amt;
}; };
std::string Item::Name(){ const std::string&Item::ActualName()const{
if(IsBlank())return "";
return it->Name();
};
const std::string Item::DisplayName()const{
if(IsBlank())return ""; if(IsBlank())return "";
std::string name=it->Name(); std::string name=ActualName();
if(IsEquippable()&&EnhancementLevel()>0){ if(IsEquippable()&&EnhancementLevel()>0){
name+=" [+"+std::to_string(EnhancementLevel())+"]"; name+=" [+"+std::to_string(EnhancementLevel())+"]";
} }
return name; return name;
}; }
bool Item::IsEquippable()const{ const bool Item::IsEquippable()const{
return Category()=="Equipment"||Category()=="Accessories"; return Category()=="Equipment"||Category()=="Accessories";
} }
std::string Item::Description(CompactText compact){ const std::string Item::Description(CompactText compact)const{
std::string description=it->Description(); std::string description=it->Description();
if(IsEquippable()){ if(IsEquippable()){
description+='\n'; description+='\n';
description+=GetStats().GetStatsString(compact); description+=GetStats().GetStatsString(compact);
if(ItemSet()){ if(ItemSet()){
const ::ItemSet*const set=ItemSet().value(); const::ItemSet*const set=ItemSet().value();
if(compact==COMPACT){ if(compact==COMPACT){
description+="\n"+set->GetSetName()+" Set - "; description+="\n"+set->GetSetName()+" Set - ";
}else{ }else{
@ -424,48 +438,52 @@ std::string Item::Description(CompactText compact){
const ITCategory Item::Category()const{ const ITCategory Item::Category()const{
return it->Category(); return it->Category();
}; };
::Decal*Item::Decal(){ const::Decal*const Item::Decal()const{
return it->Decal(); return it->Decal();
}; };
ItemScript&Item::OnUseAction(){ const ItemScript&Item::OnUseAction()const{
return it->OnUseAction(); return it->OnUseAction();
}; };
std::string ItemInfo::Name(){ const std::string&ItemInfo::Name()const{
return name; return name;
}; };
std::string ItemInfo::Description(){ const std::string&ItemInfo::Description()const{
return description; return description;
}; };
ITCategory ItemInfo::Category(){ const ITCategory ItemInfo::Category()const{
return category; return category;
}; };
::Decal*ItemInfo::Decal(){ const::Decal*const ItemInfo::Decal()const{
return img; return img;
}; };
ItemScript&ItemInfo::OnUseAction(){ const ItemScript&ItemInfo::OnUseAction()const{
return ITEM_SCRIPTS.at(useFunc); return ITEM_SCRIPTS.at(useFunc);
}; };
bool Item::IsBlank(){ const bool Item::IsBlank()const{
return amt==0||it==nullptr; return amt==0||it==nullptr;
} }
void Inventory::Clear(ITCategory itemCategory){ void Inventory::Clear(ITCategory itemCategory){
std::vector<Item>itemList=get(itemCategory); //We have to make a copy here because RemoveItem() will modify the list provided by get() inline. std::vector<Item>itemList=get(itemCategory); //We have to make a copy here because RemoveItem() will modify the list provided by get() inline.
for(Item&item:itemList){ for(Item&item:itemList){
size_t itemQuantity=GetItemCount(item.Name());//Normally we want to clear all the items that are actually in our inventory...But... size_t itemQuantity=GetItemCount(item.ActualName());//Normally we want to clear all the items that are actually in our inventory...But...
if(itemCategory=="Monster Loot"||itemCategory=="Stage Loot"){//These do not affect the actual inventory, we just clear the lists. if(itemCategory=="Monster Loot"||itemCategory=="Stage Loot"){//These do not affect the actual inventory, we just clear the lists.
itemQuantity=item.Amt(); itemQuantity=item.Amt();
} }
RemoveItem(item.Name(),itemCategory,uint32_t(itemQuantity)); RemoveItem(item.ActualName(),itemCategory,uint32_t(itemQuantity));
} }
} }
bool Item::operator==(const Item&rhs)const{ const bool Item::operator==(const Item&rhs)const{
return it==rhs.it; return it==rhs.it;
} }
const bool Item::operator==(const IT&rhs)const{
return it->Name()==rhs;
}
ItemOverlay::ItemOverlay(ItemInfo item) ItemOverlay::ItemOverlay(ItemInfo item)
:it(item),width("ItemDrop.Item Drop Scale"_F*24+4+game->GetTextSizeProp(item.Name()).x*0.5f){ :it(item),width("ItemDrop.Item Drop Scale"_F*24+4+game->GetTextSizeProp(item.Name()).x*0.5f){
xOffset=-width; xOffset=-width;
@ -487,7 +505,7 @@ void ItemOverlay::Draw(){
Pixel lightCol=Menu::GetCurrentTheme().GetButtonCol()*1.2f; Pixel lightCol=Menu::GetCurrentTheme().GetButtonCol()*1.2f;
game->GradientFillRectDecal(pos,{item.width,8},darkCol,darkCol,darkCol,lightCol); game->GradientFillRectDecal(pos,{item.width,8},darkCol,darkCol,darkCol,lightCol);
game->DrawRectDecal(pos,{item.width,8},Menu::GetCurrentTheme().GetHighlightCol()); game->DrawRectDecal(pos,{item.width,8},Menu::GetCurrentTheme().GetHighlightCol());
game->DrawDecal(pos,item.it.Decal(),{itemScale,itemScale}); game->DrawDecal(pos,const_cast<Decal*>(item.it.Decal()),{itemScale,itemScale});
game->DrawShadowStringPropDecal(pos+vf2d{itemScale*24+2,2},item.it.Name(),WHITE,BLACK,{0.5f,0.7f}); game->DrawShadowStringPropDecal(pos+vf2d{itemScale*24+2,2},item.it.Name(),WHITE,BLACK,{0.5f,0.7f});
counter++; counter++;
} }
@ -498,11 +516,11 @@ void ItemOverlay::AddToItemOverlay(const ItemInfo&it){
std::for_each(items.begin(),items.end(),[](ItemOverlay&it){it.ResetTimer();}); std::for_each(items.begin(),items.end(),[](ItemOverlay&it){it.ResetTimer();});
} }
float ItemInfo::CastTime(){ const float ItemInfo::CastTime()const{
return castTime; return castTime;
} }
float ItemInfo::CooldownTime(){ const float ItemInfo::CooldownTime()const{
return cooldownTime; return cooldownTime;
} }
@ -510,11 +528,11 @@ void ItemOverlay::ResetTimer(){
timer=0; timer=0;
} }
float Item::CastTime(){ const float Item::CastTime()const{
return it->CastTime(); return it->CastTime();
} }
float Item::CooldownTime(){ const float Item::CooldownTime()const{
return it->CooldownTime(); return it->CooldownTime();
} }
@ -524,7 +542,7 @@ const Stats&EnhancementInfo::operator[](int level)const{
const std::optional<const ItemSet *const>ItemInfo::ItemSet()const{ const std::optional<const ItemSet *const>ItemInfo::ItemSet()const{
if(ItemSet::sets.count(set)){ if(ItemSet::sets.count(set)){
return &ItemSet::sets[set]; return &ItemSet::sets.at(set);
} }
return {}; return {};
}; };
@ -560,17 +578,17 @@ EquipSlot Inventory::GetSlotEquippedIn(Item&it){
EquipSlot slot=EquipSlot(i); EquipSlot slot=EquipSlot(i);
Item*equip=GetEquip(slot); Item*equip=GetEquip(slot);
if(equip==nullptr)continue; if(equip==nullptr)continue;
if(equip->Name()==it.Name())return slot; if(equip->ActualName()==it.ActualName())return slot;
} }
return EquipSlot::NONE; return EquipSlot::NONE;
}; };
Item*Inventory::GetEquip(EquipSlot slot){ Item*Inventory::GetEquip(EquipSlot slot){
return Inventory::equipment[slot]; return Inventory::equipment[slot];
} }
EquipSlot Item::GetEquipSlot(){ const EquipSlot Item::GetEquipSlot()const{
return it->Slot(); return it->Slot();
} }
EquipSlot ItemInfo::Slot(){ const EquipSlot ItemInfo::Slot()const{
return slot; return slot;
} }
@ -600,7 +618,7 @@ void ItemInfo::InitializeSets(){
} }
} }
Stats ItemInfo::GetStats(int enhancementLevel){ const Stats&ItemInfo::GetStats(int enhancementLevel)const{
if(enhancement.size()<=enhancementLevel){ if(enhancement.size()<=enhancementLevel){
return {}; return {};
} }
@ -620,11 +638,11 @@ const std::optional<const ItemSet*const>Item::ItemSet()const{
return it->ItemSet(); return it->ItemSet();
}; };
uint8_t Item::EnhancementLevel()const{ const uint8_t Item::EnhancementLevel()const{
return enhancementLevel; return enhancementLevel;
}; };
void Item::EnhanceItem(){ void Item::EnhanceItem(){
if(enhancementLevel+1>"Item.Item Max Enhancement Level"_I)ERR("WARNING! Attempted to enhance "<<Name()<<" beyond the cap of "<<"Item.Item Max Enhancement Level"_I); if(enhancementLevel+1>"Item.Item Max Enhancement Level"_I)ERR("WARNING! Attempted to enhance "<<DisplayName()<<" beyond the cap of "<<"Item.Item Max Enhancement Level"_I);
enhancementLevel++; enhancementLevel++;
}; };
@ -665,3 +683,34 @@ ItemInfo&ItemInfo::operator[](const IT&item){
if(!ITEM_DATA.count(item))ERR("Item "<<std::quoted(item)<<" does not exist in the item database!"); if(!ITEM_DATA.count(item))ERR("Item "<<std::quoted(item)<<" does not exist in the item database!");
return ITEM_DATA[item]; return ITEM_DATA[item];
} }
const uint32_t ItemInfo::GetBuyValue()const{
return buyValue;
}
const uint32_t ItemInfo::GetSellValue()const{
return sellValue;
}
const bool ItemInfo::CanBeSold()const{
return GetSellValue()>0;
}
const bool ItemInfo::CanBePurchased()const{
return GetBuyValue()>0;
}
const uint32_t Item::BuyValue()const{
return it->GetBuyValue();
}
const uint32_t Item::SellValue()const{
return it->GetSellValue();
}
const bool Item::CanBeSold()const{
return it->CanBeSold();
}
const bool Item::CanBePurchased()const{
return it->CanBePurchased();
}
void Item::SetAmt(uint32_t newAmt){
amt=newAmt;
}

@ -44,6 +44,7 @@ All rights reserved.
#include "AttributableStat.h" #include "AttributableStat.h"
#include "BitwiseEnum.h" #include "BitwiseEnum.h"
#include <optional> #include <optional>
#include "Merchant.h"
class Crawler; class Crawler;
class ItemInfo; class ItemInfo;
@ -129,31 +130,42 @@ class Item{
friend class Inventory; friend class Inventory;
friend class Crawler; friend class Crawler;
friend class Menu; friend class Menu;
friend void Merchant::PurchaseItem(IT item,uint32_t amt);
friend void Merchant::SellItem(IT item,uint32_t amt);
private: private:
//The amount in the current item stack. //The amount in the current item stack.
uint32_t amt; uint32_t amt;
uint8_t enhancementLevel; uint8_t enhancementLevel;
ItemInfo*it; ItemInfo*it;
void SetAmt(uint32_t newAmt);
public: public:
Item(); Item();
Item(uint32_t amt,IT item,uint8_t enhancementLevel=0); Item(uint32_t amt,IT item,uint8_t enhancementLevel=0);
uint32_t Amt(); uint32_t Amt()const;
std::string Name(); //Use this for places where the item name is used for item tracking. NOT for drawing. Hooks directly into item info's base item name.
std::string Description(CompactText compact=COMPACT); const std::string&ActualName()const;
//Use for places where the item name is actually displayed. Provides modified text that shows additional information like enhancement levels.
const std::string DisplayName()const;
const std::string Description(CompactText compact=COMPACT)const;
const ITCategory Category()const; const ITCategory Category()const;
EquipSlot GetEquipSlot(); const EquipSlot GetEquipSlot()const;
::Decal*Decal(); const::Decal*const Decal()const;
const Stats GetStats()const; const Stats GetStats()const;
ItemScript&OnUseAction(); const ItemScript&OnUseAction()const;
float CastTime(); const float CastTime()const;
float CooldownTime(); const float CooldownTime()const;
bool IsBlank(); const bool IsBlank()const;
uint8_t EnhancementLevel()const; const uint8_t EnhancementLevel()const;
void EnhanceItem(); void EnhanceItem();
static Item BLANK; static Item BLANK;
bool operator==(const Item&rhs)const; const bool operator==(const Item&rhs)const;
const bool operator==(const IT&rhs)const;
const std::optional<const ::ItemSet *const>ItemSet()const; const std::optional<const ::ItemSet *const>ItemSet()const;
bool IsEquippable()const; const bool IsEquippable()const;
const uint32_t BuyValue()const;
const uint32_t SellValue()const;
const bool CanBeSold()const;
const bool CanBePurchased()const;
}; };
class Inventory{ class Inventory{
@ -220,7 +232,8 @@ class ItemInfo{
//Custom properties for this specific item's script. //Custom properties for this specific item's script.
static utils::datafile NOPROPS; static utils::datafile NOPROPS;
ItemProps customProps; ItemProps customProps;
uint32_t buyValue=0;
uint32_t sellValue=0;
private: private:
static void InitializeScripts(); static void InitializeScripts();
static void InitializeSets(); static void InitializeSets();
@ -228,20 +241,24 @@ private:
public: public:
static void InitializeItems(); static void InitializeItems();
ItemInfo(); ItemInfo();
std::string Name(); const std::string&Name()const;
std::string Description(); const std::string&Description()const;
ITCategory Category(); const ITCategory Category()const;
::Decal*Decal(); const::Decal*const Decal()const;
/* /*
For the useFunc, return true if the item can be used, false otherwise. For the useFunc, return true if the item can be used, false otherwise.
*/ */
ItemScript&OnUseAction(); const ItemScript&OnUseAction()const;
Stats GetStats(int enhancementLevel); const Stats&GetStats(int enhancementLevel)const;
float CastTime(); const float CastTime()const;
float CooldownTime(); const float CooldownTime()const;
EquipSlot Slot(); const EquipSlot Slot()const;
const std::optional<const ::ItemSet *const>ItemSet()const; const std::optional<const ::ItemSet *const>ItemSet()const;
ItemInfo&operator[](const IT&item); ItemInfo&operator[](const IT&item);
const uint32_t GetBuyValue()const;
const uint32_t GetSellValue()const;
const bool CanBeSold()const;
const bool CanBePurchased()const;
}; };
class ItemOverlay{ class ItemOverlay{

@ -78,9 +78,9 @@ void ItemDrop::Draw(){
yOffset=sin((game->levelTime+randomSpinOffset)*3)*0.5f; yOffset=sin((game->levelTime+randomSpinOffset)*3)*0.5f;
} }
game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()+yOffset},GFX["skill_overlay_icon_overlay.png"].Decal(),0,GFX["skill_overlay_icon_overlay.png"].Decal()->sprite->Size()/2,{"ItemDrop.Item Drop Scale"_F,"ItemDrop.Item Drop Scale"_F},YELLOW); game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()+yOffset},GFX["skill_overlay_icon_overlay.png"].Decal(),0,GFX["skill_overlay_icon_overlay.png"].Decal()->sprite->Size()/2,{"ItemDrop.Item Drop Scale"_F,"ItemDrop.Item Drop Scale"_F},YELLOW);
game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()+yOffset},item->Decal(),0,item->Decal()->sprite->Size()/2,{"ItemDrop.Item Drop Scale"_F,"ItemDrop.Item Drop Scale"_F},{255,255,255,128}); game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()+yOffset},const_cast<Decal*>(item->Decal()),0,item->Decal()->sprite->Size()/2,{"ItemDrop.Item Drop Scale"_F,"ItemDrop.Item Drop Scale"_F},{255,255,255,128});
game->SetDecalMode(DecalMode::ADDITIVE); game->SetDecalMode(DecalMode::ADDITIVE);
game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()+yOffset},item->Decal(),0,item->Decal()->sprite->Size()/2,{"ItemDrop.Item Drop Scale"_F,"ItemDrop.Item Drop Scale"_F},{uint8_t(abs(sin(game->levelTime*1.5)*255.f)),uint8_t(abs(sin(game->levelTime*1.5)*255.f)),uint8_t(abs(sin(game->levelTime*1.5)*255.f)),128}); game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()+yOffset},const_cast<Decal*>(item->Decal()),0,item->Decal()->sprite->Size()/2,{"ItemDrop.Item Drop Scale"_F,"ItemDrop.Item Drop Scale"_F},{uint8_t(abs(sin(game->levelTime*1.5)*255.f)),uint8_t(abs(sin(game->levelTime*1.5)*255.f)),uint8_t(abs(sin(game->levelTime*1.5)*255.f)),128});
game->SetDecalMode(DecalMode::NORMAL); game->SetDecalMode(DecalMode::NORMAL);
} }

@ -60,12 +60,12 @@ private:
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(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(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?const_cast<Decal*>(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;
} }
inline MenuItemButton(geom2d::rect<float>rect,std::vector<Item>&invRef,int invIndex,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,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,MenuFunc onHover,MenuFunc onMouseOut,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(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?const_cast<Decal*>(invRef[invIndex].Decal()):nullptr,onClick,attributes),invRef(invRef),inventoryIndex(invIndex),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){
draggable=false; draggable=false;
runHoverFunctions=true; runHoverFunctions=true;
valid=invRef.size()>invIndex; valid=invRef.size()>invIndex;
@ -73,12 +73,12 @@ public:
SetMouseOutFunc(onMouseOut); SetMouseOutFunc(onMouseOut);
} }
inline Item&GetItem(){ inline Item&GetItem(){
return Inventory::GetItem(invRef.at(inventoryIndex).Name()); return Inventory::GetItem(invRef.at(inventoryIndex).ActualName());
} }
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory. //Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory.
inline bool UseItem(uint32_t amt=1){ inline bool UseItem(uint32_t amt=1){
if(invRef.size()<=inventoryIndex)return false; if(invRef.size()<=inventoryIndex)return false;
return Inventory::UseItem(invRef.at(inventoryIndex).Name(),amt); return Inventory::UseItem(invRef.at(inventoryIndex).ActualName(),amt);
} }
inline void SetCompactDescriptions(bool compact){ inline void SetCompactDescriptions(bool compact){
if(compact)this->compact=COMPACT; if(compact)this->compact=COMPACT;
@ -98,8 +98,8 @@ protected:
std::string labelNameText; std::string labelNameText;
std::string labelDescriptionText; std::string labelDescriptionText;
if(valid){ if(valid){
icon=invRef[inventoryIndex].Decal(); icon=const_cast<Decal*>(invRef[inventoryIndex].Decal());
labelNameText=invRef[inventoryIndex].Name(); labelNameText=invRef[inventoryIndex].DisplayName();
labelDescriptionText=invRef[inventoryIndex].Description(compact); labelDescriptionText=invRef[inventoryIndex].Description(compact);
}else{ }else{
icon=nullptr; icon=nullptr;
@ -120,7 +120,7 @@ protected:
} }
virtual inline void Update(Crawler*game)override{ virtual inline void Update(Crawler*game)override{
MenuIconButton::Update(game); MenuIconButton::Update(game);
valid=invRef.size()>inventoryIndex&&ITEM_DATA.count(invRef[inventoryIndex].Name()); valid=invRef.size()>inventoryIndex&&ITEM_DATA.count(invRef[inventoryIndex].ActualName());
if(hovered){ if(hovered){
UpdateLabel(); UpdateLabel();
@ -132,7 +132,7 @@ protected:
drawutil::DrawCrosshairDecalViewPort(window,{rect.pos,rect.size},0); drawutil::DrawCrosshairDecalViewPort(window,{rect.pos,rect.size},0);
} }
if(valid){ if(valid){
int itemQuantity=Inventory::GetItemCount(invRef.at(inventoryIndex).Name()); //Normally we'd retrieve how many of this item we have from our inventory...However Monster Loot and Stage Loot inventories are special and hold their own inventory counts... int itemQuantity=Inventory::GetItemCount(invRef.at(inventoryIndex).ActualName()); //Normally we'd retrieve how many of this item we have from our inventory...However Monster Loot and Stage Loot inventories are special and hold their own inventory counts...
if(&invRef==&Inventory::get("Monster Loot")||&invRef==&Inventory::get("Stage Loot")){ if(&invRef==&Inventory::get("Monster Loot")||&invRef==&Inventory::get("Stage Loot")){
itemQuantity=invRef.at(inventoryIndex).Amt(); //So the item quantity comes from the stack itself and not our main inventory. itemQuantity=invRef.at(inventoryIndex).Amt(); //So the item quantity comes from the stack itself and not our main inventory.
} }

@ -57,12 +57,12 @@ private:
CompactText compact=COMPACT; CompactText compact=COMPACT;
public: public:
inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ :MenuIconButton(rect,(!itemRef.IsBlank())?const_cast<Decal*>(itemRef.Decal()):nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){
draggable=false; draggable=false;
valid=!itemRef.IsBlank(); valid=!itemRef.IsBlank();
} }
inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="",IconButtonAttr attributes=IconButtonAttr::SELECTABLE) inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="",IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ :MenuIconButton(rect,(!itemRef.IsBlank())?const_cast<Decal*>(itemRef.Decal()):nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){
runHoverFunctions=true; runHoverFunctions=true;
draggable=false; draggable=false;
valid=!itemRef.IsBlank(); valid=!itemRef.IsBlank();
@ -87,7 +87,7 @@ public:
icon=nullptr; icon=nullptr;
return; return;
} }
icon=itemRef.get().Decal(); icon=const_cast<Decal*>(itemRef.get().Decal());
} }
protected: protected:
virtual inline void OnMouseOut()override{ virtual inline void OnMouseOut()override{
@ -112,8 +112,8 @@ protected:
return; return;
} }
icon=itemRef.get().Decal(); icon=const_cast<Decal*>(itemRef.get().Decal());
labelNameText=itemRef.get().Name(); labelNameText=itemRef.get().DisplayName();
labelDescriptionText=itemRef.get().Description(compact); labelDescriptionText=itemRef.get().Description(compact);
if(itemNameLabelName!=""){ if(itemNameLabelName!=""){
Component<MenuLabel>(parentMenu,itemNameLabelName)->label=labelNameText; Component<MenuLabel>(parentMenu,itemNameLabelName)->label=labelNameText;

@ -37,10 +37,16 @@ All rights reserved.
#pragma endregion #pragma endregion
#include "Merchant.h" #include "Merchant.h"
#include "Crawler.h"
INCLUDE_game
std::map<Chapter,std::vector<Merchant>>Merchant::merchants; std::map<Chapter,std::vector<Merchant>>Merchant::merchants;
MerchantFunctionPrimingData Merchant::purchaseFunctionPrimed("CanPurchaseItem()");
MerchantFunctionPrimingData Merchant::sellFunctionPrimed("CanSellItem()");
Merchant Merchant::travelingMerchant;
const Merchant&Merchant::GetRandomMerchant(Chapter chapter)const{ const Merchant&Merchant::GetRandomMerchant(Chapter chapter){
return merchants[chapter][rand()%(merchants[chapter].size()-1)]; return merchants[chapter][rand()%(merchants[chapter].size()-1)];
} }
@ -57,8 +63,8 @@ Merchant&Merchant::AddMerchant(Chapter chapter){
return merchants[chapter].back(); return merchants[chapter].back();
} }
void Merchant::AddItem(IT item,uint8_t enhancementLevel){ void Merchant::AddItem(IT item,uint32_t amt,uint8_t enhancementLevel){
shopItems.push_back(Item{1,item,enhancementLevel}); shopItems.push_back(Item{amt,item,enhancementLevel});
} }
INCLUDE_DATA INCLUDE_DATA
@ -82,7 +88,12 @@ void Merchant::Initialize(){
std::string itemKey=std::format("Item[{}]",itemNumber); std::string itemKey=std::format("Item[{}]",itemNumber);
if(data.HasProperty(itemKey)){ if(data.HasProperty(itemKey)){
IT itemName=data[itemKey].GetString(); IT itemName=data[itemKey].GetString();
newMerchant.AddItem(itemName); if(data[itemKey].GetValueCount()>1){
int qty=data[itemKey].GetInt(1);
newMerchant.AddItem(itemName,qty);
}else{
newMerchant.AddItem(itemName,INFINITE);
}
}else{ }else{
ERR("Could not find item "<<itemNumber<<" in Merchant "<<merchantCount<<" of Chapter "<<chapter<<"!"); ERR("Could not find item "<<itemNumber<<" in Merchant "<<merchantCount<<" of Chapter "<<chapter<<"!");
} }
@ -96,3 +107,80 @@ void Merchant::Initialize(){
std::cout<<std::format("Added {} merchants to Chapter {}",merchantCount,chapter)<<std::endl; std::cout<<std::format("Added {} merchants to Chapter {}",merchantCount,chapter)<<std::endl;
} }
} }
bool Merchant::CanPurchaseItem(IT item,uint32_t amt)const{
bool itemAvailable=false;
const Item*foundItem=nullptr;
for(const Item&it:shopItems){
if(it==item&&it.Amt()>=amt&&it.CanBePurchased()){
itemAvailable=true;
foundItem=&it;
break;
}
}
purchaseFunctionPrimed.amt=amt;
purchaseFunctionPrimed.item=item;
return purchaseFunctionPrimed=
itemAvailable&&
foundItem!=nullptr&&
game->GetPlayer()->GetMoney()>=foundItem->BuyValue()*amt;
};
bool Merchant::CanSellItem(IT item,uint32_t amt)const{
ItemInfo&it=ITEM_DATA[item];
sellFunctionPrimed.amt=amt;
sellFunctionPrimed.item=item;
return sellFunctionPrimed=
it.CanBeSold()&&
Inventory::GetItemCount(item)>=amt;
};
void Merchant::PurchaseItem(IT item,uint32_t amt){
purchaseFunctionPrimed.Validate(item,amt);
uint32_t totalCost=0U;
for(Item&it:shopItems){
if(it==item){
if(it.Amt()!=INFINITE){
it.SetAmt(it.Amt()-amt);
}
totalCost=it.BuyValue()*amt;
break;
}
}
Inventory::AddItem(item,amt);
game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-totalCost);
purchaseFunctionPrimed=false;
};
void Merchant::SellItem(IT item,uint32_t amt){
sellFunctionPrimed.Validate(item,amt);
uint32_t totalCost=0U;
bool itemFound=false;
for(Item&it:shopItems){
if(it==item){
if(it.Amt()!=INFINITE){
it.SetAmt(it.Amt()+amt);
}
itemFound=true;
break;
}
}
if(!itemFound){
AddItem(item);
}
totalCost=ITEM_DATA[item].GetSellValue()*amt;
Inventory::RemoveItem(item,amt);
game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()+totalCost);
sellFunctionPrimed=false;
};
void Merchant::RandomizeTravelingMerchant(){
travelingMerchant=GetRandomMerchant(game->GetCurrentChapter());
};
Merchant&Merchant::GetCurrentTravelingMerchant(){
return travelingMerchant;
};

@ -35,21 +35,33 @@ Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved. All rights reserved.
*/ */
#pragma endregion #pragma endregion
#pragma once
#include "Crawler.h" #include "olcPixelGameEngine.h"
#include "FunctionPriming.h"
class Item;
using Chapter=int; using Chapter=int;
using IT=std::string;
class Merchant{ class Merchant{
public: public:
const Merchant&GetRandomMerchant(Chapter chapter)const; static void RandomizeTravelingMerchant();
static Merchant&GetCurrentTravelingMerchant();
const std::string&GetDisplayName()const; const std::string&GetDisplayName()const;
const std::vector<Item>&GetShopItems()const; const std::vector<Item>&GetShopItems()const;
void AddItem(IT item,uint8_t enhancementLevel=0U); void AddItem(IT item,uint32_t amt=1,uint8_t enhancementLevel=0U);
bool CanPurchaseItem(IT item,uint32_t amt=1U)const;
bool CanSellItem(IT item,uint32_t amt=1U)const;
void PurchaseItem(IT item,uint32_t amt=1U);
void SellItem(IT item,uint32_t amt=1U);
public: public:
static void Initialize(); static void Initialize();
static Merchant&AddMerchant(Chapter chapter); static Merchant&AddMerchant(Chapter chapter);
private: private:
static MerchantFunctionPrimingData purchaseFunctionPrimed;
static MerchantFunctionPrimingData sellFunctionPrimed;
static Merchant travelingMerchant;
static const Merchant&GetRandomMerchant(Chapter chapter);
static std::map<Chapter,std::vector<Merchant>>merchants; static std::map<Chapter,std::vector<Merchant>>merchants;
std::string displayName; std::string displayName;
std::vector<Item>shopItems; std::vector<Item>shopItems;

@ -909,3 +909,10 @@ void Player::SetBaseStat(ItemAttribute a,int val){
const std::string&ItemSet::GetSetName()const{ const std::string&ItemSet::GetSetName()const{
return name; return name;
} }
uint32_t Player::GetMoney()const{
return money;
};
void Player::SetMoney(uint32_t newMoney){
money=newMoney;
};

@ -115,6 +115,7 @@ private:
Ability useItem1; Ability useItem1;
Ability useItem2; Ability useItem2;
Ability useItem3; Ability useItem3;
uint32_t money=9999;
protected: protected:
const float ATTACK_COOLDOWN="Warrior.Auto Attack.Cooldown"_F; const float ATTACK_COOLDOWN="Warrior.Auto Attack.Cooldown"_F;
const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F; const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F;
@ -251,6 +252,9 @@ public:
void SetItem3UseFunc(Ability a); void SetItem3UseFunc(Ability a);
static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE, KEY_ITEM1, KEY_ITEM2, KEY_ITEM3; static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE, KEY_ITEM1, KEY_ITEM2, KEY_ITEM3;
uint32_t GetMoney()const;
void SetMoney(uint32_t newMoney);
}; };
struct Warrior:Player{ struct Warrior:Player{

@ -57,10 +57,10 @@ public:
MenuComponent::DrawDecal(window,focused); MenuComponent::DrawDecal(window,focused);
float scaleFactor=(rect.size.y-4)/24; float scaleFactor=(rect.size.y-4)/24;
vf2d iconSize=vf2d{scaleFactor,scaleFactor}*24.f; vf2d iconSize=vf2d{scaleFactor,scaleFactor}*24.f;
window.DrawDecal(rect.pos+vf2d{2,2},itemRef.get().Decal(),{scaleFactor,scaleFactor}); window.DrawDecal(rect.pos+vf2d{2,2},const_cast<Decal*>(itemRef.get().Decal()),{scaleFactor,scaleFactor});
window.DrawRectDecal(rect.pos+vf2d{2,2},iconSize); window.DrawRectDecal(rect.pos+vf2d{2,2},iconSize);
std::string itemName=itemRef.get().Name(); std::string itemName=itemRef.get().DisplayName();
vf2d scaledSize={std::min(1.f,(rect.size.x-6-iconSize.x)/game->GetTextSizeProp(itemName).x),1}; vf2d scaledSize={std::min(1.f,(rect.size.x-6-iconSize.x)/game->GetTextSizeProp(itemName).x),1};
window.DrawShadowStringPropDecal(rect.pos+vf2d{4,4}+vf2d{iconSize.x,iconSize.y/2-4},itemName,WHITE,BLACK,scaledSize); window.DrawShadowStringPropDecal(rect.pos+vf2d{4,4}+vf2d{iconSize.x,iconSize.y/2-4},itemName,WHITE,BLACK,scaledSize);
@ -109,7 +109,7 @@ public:
std::string labelNameText; std::string labelNameText;
std::string labelDescriptionText; std::string labelDescriptionText;
if(valid){ if(valid){
labelNameText=itemRef.get().Name(); labelNameText=itemRef.get().DisplayName();
labelDescriptionText=itemRef.get().Description(compact); labelDescriptionText=itemRef.get().Description(compact);
}else{ }else{
labelNameText=""; labelNameText="";

@ -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 4086 #define VERSION_BUILD 4125
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -5,25 +5,29 @@ Merchant
Chapter1_A Chapter1_A
{ {
DisplayName = Merchant DisplayName = Merchant
Item[1] = Minor Health Potion # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[2] = Minor Mana Potion Item[1] = Minor Health Potion,5
Item[2] = Minor Mana Potion,5
} }
Chapter1_B Chapter1_B
{ {
DisplayName = Merchant DisplayName = Merchant
Item[1] = Minor Health Potion # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[1] = Minor Health Potion,5
} }
Chapter1_C Chapter1_C
{ {
DisplayName = Merchant DisplayName = Merchant
Item[1] = Minor Mana Potion # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[1] = Minor Mana Potion,5
} }
Chapter1_D Chapter1_D
{ {
DisplayName = Merchant DisplayName = Merchant
Item[1] = Minor Health Potion # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[2] = Minor Mana Potion Item[1] = Minor Health Potion,5
Item[3] = Bandages Item[2] = Minor Mana Potion,5
Item[3] = Bandages,5
} }
} }
} }
Loading…
Cancel
Save