13using namespace Tempest;
16 return *owner->items[at];
20 return owner->items[at].get();
24 auto& cur = *owner->items[at];
29 auto& cur = *owner->items[at];
34 auto& cur = *owner->items[at];
36 if(cur.isEquipped() && subId==0)
37 return cur.equipCount();
39 return cur.count()-cur.equipCount();
46 auto& it = owner->items;
49 if(cur.isEquipped() && cur.count()>1 && subId==0) {
61 return at<owner->items.size();
65 :type(t), owner(owner) {
70void Inventory::Iterator::skipHidden() {
71 auto& it = owner->items;
73 while(at<it.size() && (it[at]->isEquipped() || it[at]->isGold()))
77 while(at<it.size() && it[at]->isEquipped()) {
91 return items.size()==0 && active==
nullptr;
98 for(
size_t i=0;i<sz;++i)
103 for(
auto& i:mdlSlots) {
107 for(
size_t i=0;i<mdlSlots.size();)
108 if(mdlSlots[i].item==
nullptr) {
109 mdlSlots[i] = std::move(mdlSlots.back());
115 s.
read(ammotSlot.slot);
116 ammotSlot.item = readPtr(s);
117 s.
read(stateSlot.slot);
118 stateSlot.item = readPtr(s);
138 else if(3<=
id &&
id<10)
139 active=&numslot[
id-3];
140 s.
read(curItem,stateItem);
147 implLoad(&owner,owner.
world(),s);
151 implLoad(
nullptr,w,s);
155 uint32_t sz=uint32_t(items.size());
160 sz=uint32_t(mdlSlots.size());
162 for(
auto& i:mdlSlots){
163 fout.
write(i.slot,indexOf(i.item));
165 fout.
write(ammotSlot.slot,indexOf(ammotSlot.item));
166 fout.
write(stateSlot.slot,indexOf(stateSlot.item));
168 fout.
write(indexOf(armor) );
169 fout.
write(indexOf(belt) );
170 fout.
write(indexOf(amulet));
171 fout.
write(indexOf(ringL) );
172 fout.
write(indexOf(ringR) );
173 fout.
write(indexOf(melee) );
174 fout.
write(indexOf(range) );
175 fout.
write(indexOf(shield));
177 fout.
write(indexOf(i));
182 else if(active==&range)
185 if(active==&numslot[i])
188 fout.
write(curItem,stateItem);
205 return i->sellCost();
228 const auto cls = p->clsId();
230 Item* it=findByClass(cls);
233 items.emplace_back(std::move(p));
234 return items.back().get();
237 it->
handle().owner = p->handle().owner;
238 it->
handle().owner_guild = p->handle().owner_guild;
244 auto& vm = owner.
script();
247 return addItem(
id,count,owner);
256 Item* it=findByClass(itemSymbol);
261 items.emplace_back(std::move(ptr));
262 return items.back().get();
264 catch(
const std::runtime_error& call) {
265 Log::e(
"[invalid call in VM, while initializing item: ",itemSymbol,
"]");
277 Item* it=findByClass(itemSymbol);
278 return delItem(it,count,owner);
285 if(it->
count()>count)
296 for(
size_t i=0;i<mdlSlots.size();)
297 if(mdlSlots[i].item==it) {
298 mdlSlots[i] = std::move(mdlSlots.back());
305 for(
size_t i=0;i<items.size();++i)
306 if(items[i]->clsId()==it->
clsId()){
307 items.erase(items.begin()+
int(i));
313 for(
size_t i=0;i<from.items.size();++i){
314 auto& it = *from.items[i];
315 if(it.
clsId()!=itemSymbol)
324 if(it.
count()==count) {
326 if(fromNpc==
nullptr){
327 Log::e(
"Inventory: invalid transfer call");
332 to.
addItem(std::move(from.items[i]));
333 from.items.erase(from.items.begin()+
int(i));
336 to.
addItem(itemSymbol,count,wrld);
346 Item* it=findByClass(cls);
355 setSlot(armor,
nullptr,owner,
false);
359 setSlot(belt,
nullptr,owner,
false);
363 setSlot(amulet,
nullptr,owner,
false);
367 setSlot(ringL,
nullptr,owner,
false);
371 setSlot(ringR,
nullptr,owner,
false);
375 setSlot(melee,
nullptr,owner,
false);
379 setSlot(range,
nullptr,owner,
false);
383 setSlot(shield,
nullptr,owner,
false);
389 setSlot(i,
nullptr,owner,
false);
392 Log::e(
"[",owner.
displayName().data(),
"] inconsistent inventory state");
393 setSlot(it,
nullptr,owner,
false);
397bool Inventory::setSlot(
Item *&slot,
Item* next,
Npc& owner,
bool force) {
401 int32_t atr=0,nValue=0,plMag=0,itMag=0;
414 auto& itData = slot->
handle();
415 auto mainFlag =
ItmFlags(itData.main_flag);
418 applyArmor(*slot,owner,-1);
422 applyWeaponStats(owner,*slot,-1);
437 vm.
invokeItem(&owner,uint32_t(itData.on_unequip));
443 auto& itData = next->
handle();
447 applyArmor(*slot,owner,1);
455 applyWeaponStats(owner,*slot,1);
457 vm.
invokeItem(&owner,uint32_t(itData.on_equip));
462 auto& world = owner.
world();
470 for(
auto& i:mdlSlots) {
471 auto vbody = world.
addView(i.item->handle());
474 if(ammotSlot.item!=
nullptr) {
475 auto vbody = world.
addView(ammotSlot.item->handle());
476 owner.
setAmmoItem(std::move(vbody),ammotSlot.slot);
478 if(stateSlot.item!=
nullptr) {
479 auto vitm = world.
addView(stateSlot.item->handle());
488 auto& itData = armor->
handle();
489 auto flag =
ItmFlags(itData.main_flag);
500 auto vbody = owner.
world().addView(melee->
handle());
512 auto vbody = owner.
world().addView(range->
handle());
518 if(shield==
nullptr) {
525 auto vbody = owner.
world().addView(shield->
handle());
531 if(active==
nullptr || *active==
nullptr)
535 if(!sp->isSpellOrRune())
538 const VisualFx* vfx = owner.
world().script().spellVfx(sp->spellId());
543 auto a = bestMeleeWeapon(owner);
545 setSlot(melee,a,owner,
false);
549 auto a = bestRangedWeapon(owner);
551 setSlot(range,a,owner,
false);
555 setSlot(melee,
nullptr,owner,
false);
556 setSlot(range,
nullptr,owner,
false);
557 setSlot(shield,
nullptr,owner,
false);
561 setSlot(armor,
nullptr,owner,
false);
565 std::vector<std::unique_ptr<Item>> used;
567 if(i->isEquipped() || (i->isMission() && !includeMissionItm)){
568 used.emplace_back(std::move(i));
570 items = std::move(used);
574 std::vector<std::unique_ptr<Item>> used;
576 if(i->isMission() && !includeMissionItm){
577 used.emplace_back(std::move(i));
579 items = std::move(used);
584 if(i->spellId()==splId)
603 uint32_t munition = 0;
605 uint32_t cls = uint32_t(i->handle().munition);
606 if(cls>0 && cls!=munition) {
629 if(active!=
nullptr && *active!=
nullptr)
630 applyWeaponStats(owner,**active,-1);
641 if(3<=slot && slot<=10)
642 next=&numslot[slot-3];
645 if(next!=
nullptr && *next!=
nullptr)
648 if(active!=
nullptr && *active!=
nullptr)
649 applyWeaponStats(owner,**active,1);
653 for(uint8_t i=0;i<8;++i) {
655 if(s!=
nullptr && s->isSpellOrRune() && s->spellId()==spell){
663 if(i->spellId()==spell){
664 setSlot(numslot[0],i.get(),owner,
true);
672 for(uint8_t i=0;i<8;++i){
673 if(active==&numslot[i])
680 return stateSlot.item!=
nullptr || stateItem!=0;
690 implPutState(owner,
size_t(stateItem),slot);
696 Item* it=findByClass(cls);
700 for(
auto& i:mdlSlots)
708 mdlSlots.emplace_back();
709 MdlSlot& sl = mdlSlots.back();
718 const bool all = slot.empty();
719 for(
size_t i=0;i<mdlSlots.size();)
720 if(all || mdlSlots[i].slot==slot) {
722 auto last = mdlSlots[i].item;
723 mdlSlots[i] = mdlSlots.back();
731 if(all || stateSlot.slot==slot) {
732 if(stateSlot.item!=
nullptr)
734 implPutState(owner,0,stateSlot.slot);
740 Item* it = (cls==0 ? nullptr : findByClass(cls));
742 ammotSlot.slot.clear();
743 ammotSlot.item =
nullptr;
748 ammotSlot.slot = slot;
750 auto& itData = it->
handle();
751 auto vitm = owner.
world().addView(itData);
755void Inventory::implPutState(
Npc& owner,
size_t cls, std::string_view slot) {
756 Item* it = (cls==0 ? nullptr : findByClass(cls));
758 stateSlot.slot.clear();
759 stateSlot.item =
nullptr;
764 stateSlot.slot = slot;
771 Item* it = (cls==0 ? nullptr : findByClass(cls));
790 std::string_view zsSlot =
"ZS_SLOT";
792 auto& world = owner.
world();
793 auto& slot = invNpc.mdlSlots.back();
795 auto vbody = world.
addView(slot.item->handle());
799 MdlSlot& sl = mobsi.
inventory().mdlSlots.back();
803 auto itm = slot.item;
805 invNpc.mdlSlots.pop_back();
810 curItem = int32_t(cls);
814 stateItem = int32_t(cls);
817bool Inventory::equipNumSlot(
Item *next, uint8_t slotHint,
Npc &owner,
bool force) {
819 return setSlot(numslot[slotHint-3],next,owner,force);
822 for(
auto& i:numslot) {
824 setSlot(i,next,owner,force);
831void Inventory::applyArmor(
Item &it,
Npc &owner, int32_t sgn) {
839 Item* it=findByClass(cls);
843 auto& itData = it->
handle();
844 auto mainflag =
ItmFlags(itData.main_flag);
848 return setSlot(shield,it,owner,force);
851 return setSlot(melee,it,owner,force);
854 return setSlot(range,it,owner,force);
861 return equipNumSlot(it,slotHint,owner,force);
865 return setSlot(armor,it,owner,force);
868 return setSlot(belt,it,owner,force);
871 return setSlot(amulet,it,owner,force);
875 return setSlot(ringL,it,owner,force);
877 return setSlot(ringR,it,owner,force);
881 bool deleteLater =
false;
897 if(itData.on_state[0]!=0){
898 auto& vm = owner.
world().script();
899 vm.
invokeItem(&owner,uint32_t(itData.on_state[0]));
909 Item* it=findByClass(cls);
946 auto it = findByClass(
size_t(cls));
956 auto a = bestArmor(owner);
958 setSlot(armor,a,owner,
false);
961Item *Inventory::findByClass(
size_t cls) {
974 auto& itData = i->
handle();
975 auto flag =
ItmFlags(itData.main_flag);
988 int32_t value = std::numeric_limits<int32_t>::min();
989 int32_t damage = std::numeric_limits<int32_t>::min();
991 auto& itData = i->handle();
992 auto flag =
ItmFlags(itData.main_flag);
995 if(!i->checkCond(owner))
997 if(itData.munition>0 && findByClass(
size_t(itData.munition))==
nullptr)
1000 if(std::make_tuple(itData.damage_total, itData.value)>std::make_tuple(damage, value)){
1002 damage = itData.damage_total;
1003 value = itData.value;
1009Item *Inventory::bestArmor(
Npc &owner) {
1013Item *Inventory::bestMeleeWeapon(
Npc &owner) {
1017Item *Inventory::bestRangedWeapon(
Npc &owner) {
1021void Inventory::applyWeaponStats(
Npc& owner,
const Item &weapon,
int sgn) {
1022 auto& hnpc = owner.
handle();
1024 for(
size_t i=0; i<zenkit::DamageType::NUM; ++i){
1025 hnpc.damage[i] += sgn*weapon.
handle().damage[i];
1026 if(weapon.
handle().damage_type & (1<<i)) {
1027 hnpc.damage[i] += sgn*weapon.
handle().damage_total;
1032 for(
size_t i=0; i<zenkit::DamageType::NUM; ++i) {
1033 assert(hnpc.damage[i]>=0);
1037void Inventory::sortItems()
const {
1041 std::sort(items.begin(),items.end(),[](std::unique_ptr<Item>& l, std::unique_ptr<Item>& r){
1046bool Inventory::less(
const Item &il,
const Item &ir) {
1047 auto ordL = orderId(il);
1048 auto ordR = orderId(ir);
1055 int32_t lV = 0, rV = 0;
1068int Inventory::orderId(
const Item& i) {
1072 for(
size_t i=0; i<invCatOrder.size(); ++i)
1073 if(mflg!=0 && (mflg&invCatOrder[i]))
1075 return int(invCatOrder.size());
1078uint8_t Inventory::slotId(
Item *&slt)
const {
1085 for(
auto& i:numslot){
1094uint32_t Inventory::indexOf(
const Item *it)
const {
1096 return uint32_t(-1);
1097 for(
size_t i=0;i<items.size();++i)
1098 if(items[i].get()==it)
1100 return uint32_t(-1);
1104 uint32_t v=uint32_t(-1);
1107 return items[v].get();
size_t findSymbolIndex(std::string_view s)
void printCannotCastError(Npc &npc, int32_t plM, int32_t itM)
void printCannotUseError(Npc &npc, int32_t atr, int32_t nValue)
void invokeItem(Npc *npc, ScriptFn fn)
static auto invCatOrder() -> const std::vector< ItmFlags > &
void setSlotItem(MeshObjects::Mesh &&itm, std::string_view slot)
const Item & operator*() const
const Item * operator->() const
void updateRuneView(Npc &owner)
void unequipArmor(GameScript &vm, Npc &owner)
Item * findByFlags(ItmFlags f, uint32_t num) const
void updateBowView(Npc &owner)
int32_t sellPriceOf(size_t item) const
void clear(GameScript &vm, Npc &owner, bool includeMissionItm=false)
void equipBestArmor(Npc &owner)
void setCurrentItem(size_t cls)
bool hasStateItem() const
bool hasRangedWeaponWithAmmo() const
void equipArmor(int32_t cls, Npc &owner)
bool putState(Npc &owner, size_t cls, int state)
void equipBestMeleeWeapon(Npc &owner)
bool equip(size_t cls, Npc &owner, bool force)
void putToSlot(Npc &owner, size_t cls, std::string_view slot)
void switchActiveWeaponFist()
Iterator iterator(IteratorType t) const
static void transfer(Inventory &to, Inventory &from, Npc *fromNpc, size_t cls, size_t count, World &wrld)
void invalidateCond(Npc &owner)
bool unequip(size_t cls, Npc &owner)
bool use(size_t cls, Npc &owner, uint8_t slotHint, bool force)
const Item * activeWeapon() const
void updateArmorView(Npc &owner)
void switchActiveWeapon(Npc &owner, uint8_t slot)
uint8_t currentSpellSlot() const
void switchActiveSpell(int32_t spell, Npc &owner)
void updateSwordView(Npc &owner)
void putAmmunition(Npc &owner, size_t cls, std::string_view slot)
bool hasSpell(int32_t spl) const
Item * addItem(std::unique_ptr< Item > &&p)
void delItem(size_t cls, size_t count, Npc &owner)
int32_t priceOf(size_t item) const
static void moveItem(Npc &owner, Inventory &invNpc, Interactive &mobsi)
void putCurrentToSlot(Npc &owner, std::string_view slot)
void equipBestRangedWeapon(Npc &owner)
void load(Serialize &s, Npc &owner)
void unequipWeapons(GameScript &vm, Npc &owner)
void autoEquipWeapons(Npc &owner)
bool clearSlot(Npc &owner, std::string_view slot, bool remove)
bool hasMissionItems() const
void setStateItem(size_t cls)
void save(Serialize &s) const
size_t itemCount(const size_t id) const
Item * getItem(size_t instance)
void updateView(Npc &owner)
void updateShieldView(Npc &owner)
bool checkCondRune(const Npc &other, int32_t &cPl, int32_t &cIt) const
ItmFlags mainFlag() const
void setCount(size_t cnt)
bool checkCond(const Npc &other) const
const zenkit::IItem & handle() const
void setAsEquipped(bool e)
bool checkCondUse(const Npc &other, int32_t &atr, int32_t &nv) const
int32_t protection(Protection p) const
auto weaponState() const -> WeaponState
void setRangedWeapon(MeshObjects::Mesh &&bow)
void setShield(MeshObjects::Mesh &&shield)
void changeProtection(Protection p, int32_t val)
void setSlotItem(MeshObjects::Mesh &&itm, std::string_view slot)
auto inventory() const -> const Inventory &
bool setAnimItem(std::string_view scheme, int state)
std::string_view displayName() const
void setSword(MeshObjects::Mesh &&sword)
void setStateItem(MeshObjects::Mesh &&itm, std::string_view slot)
void delItem(size_t id, uint32_t amount)
void clearSlotItem(std::string_view slot)
void setMagicWeapon(Effect &&spell)
void setAmmoItem(MeshObjects::Mesh &&itm, std::string_view slot)
void write(const Arg &... a)
MeshObjects::Mesh addView(std::string_view visual) const
GameScript & script() const
static CommandLine * instance