• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

C++ Quiver for Nostalrius 7.7

Sequax

Member
Joined
Oct 24, 2008
Messages
19
Reaction score
9
Hey, been trying to figure out how to get a quiver to work on Nostalrius 7.7.

Here the git for the sources I'm using: GitHub

I've tried looking at these two tutorials but my players.cpp doesn't match. I don't have any "ammoItem".
Quiver [TFS 1.X + 0.X]
Quiver for paladins - tfs1.X

I don't know that much about coding, I usually just look at what other people have done and try to figure out the patterns, but in this case, I see none. I can find places where it says AMMO_NONE in different files just as the tutorials, but it always comes down to "ammoItem" which is missing for me.

For the record I'm not particularly interested in setting a limit as said in the first tutorial.

Any ideas? Would be much appreciated.

Here's what I've found that seems kind of similar:

player.cpp
C++:
Item* Player::getAmmunition() const
{
return inventory[CONST_SLOT_AMMO];
}

item.cpp
C++:
    } else if (it.weaponType != WEAPON_NONE) {
        if (it.weaponType == WEAPON_DISTANCE && it.ammoType != AMMO_NONE) {
            if (it.attack != 0) {
                s << ", Atk" << std::showpos << it.attack << std::noshowpos;
            }
        } else if (it.weaponType != WEAPON_AMMO && it.weaponType != WEAPON_WAND && (it.attack != 0 || it.defense != 0)) {
            s << " (";
            if (it.attack != 0) {
                s << "Atk:" << static_cast<int>(it.attack);
            }

            if (it.defense != 0) {
                if (it.attack != 0)
                    s << " ";

combat.cpp
C++:
        if (weapon->getWeaponType() == WEAPON_DISTANCE) {
            ammunition = player->getAmmunition();
            if (weapon->getAmmoType() != AMMO_NONE) {
                if (!ammunition || weapon->getAmmoType() != ammunition->getAmmoType()) {
                    // redirect to fist fighting
                    return closeAttack(attacker, target, fightMode);
                }
C++:
                if (weapon->getAmmoType() != AMMO_NONE) {
                    Item* ammunition = player->getAmmunition();
                    if (ammunition && ammunition->getAmmoType() == weapon->getAmmoType()) {
                        attackValue += ammunition->getAttack();
                    }
                }

C++:
        if (ammunition && weapon->getAmmoType() != AMMO_NONE && weapon->getAmmoType() == ammunition->getAmmoType()) {
            hitChance = 90; // bows and crossbows
            specialEffect = ammunition->getWeaponSpecialEffect();
            attackStrength = ammunition->getAttackStrength();
            attackVariation = ammunition->getAttackVariation();
            if (normal_random(0, 100) <= ammunition->getFragility()) {
                uint16_t count = ammunition->getItemCount();
                if (count > 1) {
                    g_game.transformItem(ammunition, ammunition->getID(), count - 1);
                } else {
                    g_game.internalRemoveItem(ammunition);
                }
            }

            moveWeapon = false;
        }

items.cpp
C++:
                        items[id].ammoType = getAmmoType(script.readIdentifier());
                        if (items[id].ammoType == AMMO_NONE) {
                            script.error("Unknown ammo type");
                            return false;
 
Solution
I can't help you much, only explain some things

in player.cpp(line 180) i add
C++:
    if (Item* cylinderItem = toCylinder->getItem()){
        if (cylinderItem->isQuiver() && item->getWeaponType() != WEAPON_AMMO){
            Player* player = actor->getPlayer();
            if(player){
                std::ostringstream ss;
                ss << "Only ammunition accepted in that container.";
                player->sendCancelMessage(ss.str());
                    return ret;
            }
        }
    }

That's because it doesn't belong there. As you can see, it sends a message saying that "Only ammunition is accepted in that container", so it has something to do with moving items to the quiver. Also, the errors indicate...
I developed a quiver for it, my tip is: try to make a new flag, like itemType = quiver.

Its more easily to organize.
1568635721122.png
1568635755774.png
1568635917500.png
ps:
wtff...
thats a active member

1568635590245.png
 
Thanks for the input. I have a few questions however, because this doesn't really make sense to me.

So it looks like in your first pic you just added that line in items.cpp, that's pretty straight forward. But then I don't really understand where the code in your second pic should go. Is it in items.h? I tried to compile with it and got this error:

C++:
In file included from /XXX/item.h:25,
                 from /XXX/bed.h:23,
                 from /XXX/actions.cpp:23:
/XXX/items.h: In member function ‘bool ItemType::isQuiver() const’:
/XXX/items.h:131:11: error: ‘items’ was not declared in this scope
    return items[id].isQuiver();
/XXX/items.h:131:11: note: suggested alternative: ‘item_t’
    return items[id].isQuiver();

Now to your third pic. Is that supposed to be in player.cpp? My best guess was to put it under "Item* Player::getWeapon() const. But that was a shot in the dark really. I have absolutely no idea where that's supposed to be.

Like I said, I don't really know the coding rules or language, I just doing my best to follow the logic in other people's work, so if you don't mind, be more like "This goes here and this goes there" and such.

I really appreciate the help though!
 
Thanks for the input. I have a few questions however, because this doesn't really make sense to me.

So it looks like in your first pic you just added that line in items.cpp, that's pretty straight forward. But then I don't really understand where the code in your second pic should go. Is it in items.h? I tried to compile with it and got this error:

C++:
In file included from /XXX/item.h:25,
                 from /XXX/bed.h:23,
                 from /XXX/actions.cpp:23:
/XXX/items.h: In member function ‘bool ItemType::isQuiver() const’:
/XXX/items.h:131:11: error: ‘items’ was not declared in this scope
    return items[id].isQuiver();
/XXX/items.h:131:11: note: suggested alternative: ‘item_t’
    return items[id].isQuiver();

Now to your third pic. Is that supposed to be in player.cpp? My best guess was to put it under "Item* Player::getWeapon() const. But that was a shot in the dark really. I have absolutely no idea where that's supposed to be.

Like I said, I don't really know the coding rules or language, I just doing my best to follow the logic in other people's work, so if you don't mind, be more like "This goes here and this goes there" and such.

I really appreciate the help though!
item.h, inside of class Item underneath where all other methods use items[id], use ctrl+f to find it.
 
Alrigth so here's what I've done so far:

in item.h I just add this (line 714):
C++:
        bool isQuiver() const {
            return items[id].isQuiver();

in items.cpp I add (line 116)
C++:
else if (identifier == "quiver") {
                        items[id].group = ITEM_GROUP_QUIVER;
                    }
in player.cpp(line 180) i add
C++:
    if (Item* cylinderItem = toCylinder->getItem()){
        if (cylinderItem->isQuiver() && item->getWeaponType() != WEAPON_AMMO){
            Player* player = actor->getPlayer();
            if(player){
                std::ostringstream ss;
                ss << "Only ammunition accepted in that container.";
                player->sendCancelMessage(ss.str());
                    return ret;
            }
        }
    }

in items.h I add (line 166)
C++:
        bool isQuiver() const {
            return type == ITEM_TYPE_QUIVER;

Also in items.h (line 57)
C++:
    ITEM_TYPE_QUIVER,

also in items.h (line 77)
C++:
GROUP_TYPE_QUIVER,

At first a was stuggeling a bit with the item.h / items.cpp, but after a while I stopped getting errors. However with player.cpp I can't seem to find a solution. I keep getting error about toCylinder. I messed around with it quite a bit, but I really can't figure it out. This is the error I get when I try to compile it.

Code:
/XXX/player.cpp: In member function ‘Item* Player::getWeapon() const’:
/XXX/player.cpp:180:27: error: ‘toCylinder’ was not declared in this scope
  if (Item* cylinderItem = toCylinder->getItem()){
/XXX/player.cpp:180:27: note: suggested alternative: ‘Cylinder’
  if (Item* cylinderItem = Cylinder->getItem()){
/XXX/player.cpp:182:21: error: ‘actor’ was not declared in this scope
    Player* player = actor->getPlayer();
/XXX/player.cpp:182:21: note: suggested alternative: ‘wctob’
    Player* player = wctob->getPlayer();
/XXX/player.cpp:187:13: error: ‘ret’ was not declared in this scope
      return ret;

Any ideas?

Here's my full files if you want to check for reference (pastebin):

items.h
items.cpp
item.h
player.cpp
 
I can't help you much, only explain some things

in player.cpp(line 180) i add
C++:
    if (Item* cylinderItem = toCylinder->getItem()){
        if (cylinderItem->isQuiver() && item->getWeaponType() != WEAPON_AMMO){
            Player* player = actor->getPlayer();
            if(player){
                std::ostringstream ss;
                ss << "Only ammunition accepted in that container.";
                player->sendCancelMessage(ss.str());
                    return ret;
            }
        }
    }

That's because it doesn't belong there. As you can see, it sends a message saying that "Only ammunition is accepted in that container", so it has something to do with moving items to the quiver. Also, the errors indicate that variables "toCylinder" and "actor" do not exist.

About the getWeapon function, it seems that your source's function has been changed in relation to the original TFS

So when comparing the two example quivers you linked, you should probably do something inside getAmmunition to loop the quiver and find its ammos if the slot item isn't ammunition (similar to how they do).

I hope this helps you.

-- EDIT

I have not tested and can't, but your getAmmunition function should be something like this, I think:

C++:
Item* Player::getAmmunition() const
{
    Item* item = inventory[CONST_SLOT_AMMO];
    if(!item)
        return nullptr;

    if(Container *container = item->getContainer()) {
        Item* weapon = getWeapon();
        const ItemType& it = Item::items[weapon->getID()];
        for(ContainerIterator iter = container->iterator(); iter.hasNext(); iter.advance()) {
            const ItemType& itr = Item::items[(*iter)->getID()];
            if(itr.ammoType == it.ammoType)
                return (*iter);
        }
    }

    return item;
}
 
Last edited:
Solution
C++:
Item* Player::getAmmunition() const
{
    Item* item = inventory[CONST_SLOT_AMMO];
    if(!item)
        return nullptr;

    if(Container *container = item->getContainer()) {
        Item* weapon = getWeapon();
        const ItemType& it = Item::items[weapon->getID()];
        for(ContainerIterator iter = container->iterator(); iter.hasNext(); iter.advance()) {
            const ItemType& itr = Item::items[(*iter)->getID()];
            if(itr.ammoType == it.ammoType)
                return (*iter);
        }
    }

    return item;
}

I can't beleive it. It actually worked! No errors or anything!

Thank you so much! You have no idea how many hours I spent trying to solve this haha
 
hello!

im using a TFS 1.2 Nostalrius too and it also worked for me. But the point is for every type of container item that i put on arrow slot can be used like a quiver, so now im trying understand how to deal with that, any ideas?
 
Hello everyone, sorry for posting on a pretty old thread but I think I managed to workaround a pretty good fix for this quiver system for Nostalrius and I just wanted to share it. I would for sure not call myself a coder or anything so I'm sorry if my fix seem brutish or amateur, I just wanted to share it to other people so that they can use it if they want to. :)



Go go const.h in sources, search for "ITEM_AMULETOFLOSS = 3057," and below it add


C++:
ITEM_AMMOQUIVER = 5114,  //ID of the Quiver you want.



Then we use this altered code that @leleco95 created:



C++:
Item* Player::getAmmunition() const

{

    Item* item = inventory[CONST_SLOT_AMMO];
    if (!item)
        return nullptr;



    if (inventory[CONST_SLOT_AMMO] && inventory[CONST_SLOT_AMMO]->getID() == ITEM_AMMOQUIVER) {
        if (Container* container = item->getContainer()) {
            Item* weapon = getWeapon();
            const ItemType& it = Item::items[weapon->getID()];
            for (ContainerIterator iter = container->iterator(); iter.hasNext(); iter.advance()) {
                const ItemType& itr = Item::items[(*iter)->getID()];
                if (itr.ammoType == it.ammoType)
                    return (*iter);
            }
        }
    }


   return item;

}



Then the last bit of changes we want to add is go to container.cpp, find the "ReturnValue Container::queryAdd" function, just above the line "const Cylinder* cylinder = getParent();" paste


C++:
if (getName() == "quiver" && (!(item->getSlotPosition() & SLOTP_AMMO) || item->getSlotPosition() & SLOTP_BACKPACK)) {
        return RETURNVALUE_NOTENOUGHROOM;
    }



And then scroll down to the function right below it called "ReturnValue Container::queryMaxCount" and paste



C++:
if (getName().find("quiver") != std::string::npos && !(item->getSlotPosition() & SLOTP_AMMO)) {
        return RETURNVALUE_NOTENOUGHROOM;
    }



Sorry if my explanation or process is bad, I've never really helped or posted something like this to OTLand so just wanted to help out when I felt I could for the first time ever. This makes it so that you have a working quiver and any item that is a bag/backpack cannot be put inside it either.

Note that this is not working 100% as it only makes it so any item with the Backpack flag cannot be put it, it can still contain presents and other containers, I'm just not 100% sure how to change that.
 

Similar threads

Back
Top