• 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!

TFS 1.X+ [C++] item attack speed (attr key not recognized)

Status
Not open for further replies.

Cornwallis

Member
Joined
Jan 3, 2010
Messages
480
Reaction score
16
Hello, so I'm trying to have attack speed on each weapon. No errors on compiling, only this error in console:
Code:
 [Warning - Items::parseItemNode] Unknown key value: attackspeed
It also doesn't work if it's attackSpeed.
Here's what I've done:
items.cpp
Code:
        } else if (tmpStrValue == "attack") {
            it.attack = pugi::cast<int32_t>(valueAttribute.value());
        } else if (tmpStrValue == "attackspeed") {
            it.attackSpeed = pugi::cast<int32_t>(valueAttribute.value());
I placed attackspeed in here:
Code:
ItemType::ItemType() :
    group(ITEM_GROUP_NONE), type(ITEM_TYPE_NONE), id(0), clientId(0),
    stackable(false), isAnimation(false), weight(0), levelDoor(0), decayTime(0),
    wieldInfo(0), minReqLevel(0), minReqMagicLevel(0), charges(0), maxHitChance(-1),
    decayTo(-1), attack(0), attackSpeed(0),  defense(0), extraDefense(0), armor(0), rotateTo(0),
    runeMagLevel(0), runeLevel(0), combatType(COMBAT_NONE), transformToOnUse(),
    transformToFree(0), destroyTo(0), maxTextLen(0), writeOnceItemId(0),
    transformEquipTo(0), transformDeEquipTo(0), maxItems(8), slotPosition(SLOTP_HAND),
    speed(0), wareId(0), magicEffect(CONST_ME_NONE), bedPartnerDir(DIRECTION_NONE),
    weaponType(WEAPON_NONE), ammoType(AMMO_NONE), shootType(CONST_ANI_NONE),
    corpseType(RACE_NONE), fluidSource(FLUID_NONE), floorChange(0),
    alwaysOnTopOrder(0), lightLevel(0), lightColor(0), shootRange(1), hitChance(0),
    forceUse(false), hasHeight(false), walkStack(true), blockSolid(false),
    blockPickupable(false), blockProjectile(false), blockPathFind(false),
    allowPickupable(false), showDuration(false), showCharges(false),
    showAttributes(false), replaceable(true), pickupable(false), rotatable(false),
    useable(false), moveable(false), alwaysOnTop(false), canReadText(false),
    canWriteText(false), isVertical(false), isHorizontal(false), isHangable(false),
    allowDistRead(false), lookThrough(false), stopTime(false), showCount(true)

tools.cpp:
Code:
    } else if (str == "attack") {
        return ITEM_ATTRIBUTE_ATTACK;
    } else if (str == "attackSpeed") {
        return ITEM_ATTRIBUTE_ATTACKSPEED;

luascript.cpp:
Code:
    registerEnum(ITEM_ATTRIBUTE_ATTACK)
    registerEnum(ITEM_ATTRIBUTE_ATTACKSPEED)
Code:
    registerMethod("ItemType", "getAttack", LuaScriptInterface::luaItemTypeGetAttack);
    registerMethod("ItemType", "getAttackSpeed", LuaScriptInterface::luaItemTypeGetAttackSpeed);
Code:
int LuaScriptInterface::luaItemTypeGetAttack(lua_State* L)
{
    // itemType:getAttack()
    const ItemType* itemType = getUserdata<const ItemType>(L, 1);
    if (itemType) {
        lua_pushnumber(L, itemType->attack);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

int LuaScriptInterface::luaItemTypeGetAttackSpeed(lua_State* L)
{
    // itemType:getAttackSpeed()
    const ItemType* itemType = getUserdata<const ItemType>(L, 1);
    if (itemType) {
        lua_pushnumber(L, itemType->attackSpeed);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

item.cpp:
Code:
        case ATTR_ATTACK: {
            int32_t attack;
            if (!propStream.read<int32_t>(attack)) {
                return ATTR_READ_ERROR;
            }

            setIntAttr(ITEM_ATTRIBUTE_ATTACK, attack);
            break;
        }

        case ATTR_ATTACKSPEED: {
            int32_t attackSpeed;
            if (!propStream.read<int32_t>(attackSpeed)) {
                return ATTR_READ_ERROR;
            }

            setIntAttr(ITEM_ATTRIBUTE_ATTACKSPEED, attackSpeed);
            break;
        }
Code:
    if (hasAttribute(ITEM_ATTRIBUTE_ATTACK)) {
        propWriteStream.write<uint8_t>(ATTR_ATTACK);
        propWriteStream.write<int32_t>(getIntAttr(ITEM_ATTRIBUTE_ATTACK));
    }
  
    if (hasAttribute(ITEM_ATTRIBUTE_ATTACKSPEED)) {
        propWriteStream.write<uint8_t>(ATTR_ATTACKSPEED);
        propWriteStream.write<int32_t>(getIntAttr(ITEM_ATTRIBUTE_ATTACKSPEED));
    }
Code:
            int32_t attack;
            int32_t attackSpeed;
            int8_t hitChance;
            if (item) {
                attack = item->getAttack();
                hitChance = item->getHitChance();
                attackSpeed = item->getAttackSpeed();
            } else {
                attack = it.attack;
                hitChance = it.hitChance;
                attackSpeed = it.attackSpeed;
            }

            if (attack != 0) {
                s << ", Atk" << std::showpos << attack << std::noshowpos;
            }
          
            if (attackSpeed != 0) {
                s << ", AtkSpd" << std::showpos << attackSpeed << std::noshowpos;
            }
Code:
            int32_t attack, attackSpeed, defense, extraDefense;
            if (item) {
                attack = item->getAttack();
                attackSpeed = item->getAttackSpeed();
                defense = item->getDefense();
                extraDefense = item->getExtraDefense();
            } else {
                attack = it.attack;
                attackSpeed = it.attackSpeed;
                defense = it.defense;
                extraDefense = it.extraDefense;
            }

            if (attack != 0) {
                begin = false;
                s << " (Atk:" << attack;

                if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0) {
                    s << " physical + " << it.abilities->elementDamage << ' ' << getCombatName(it.abilities->elementType);
                }
            }
          
            if (attackSpeed != 0) {
                if (begin) {
                    begin = false;
                    s << " (";
                } else {
                    s << ", ";
                }
                s << "AtkSpd:" << attackSpeed;
            }

item.h:
Code:
        int32_t getAttack() const {
            if (hasAttribute(ITEM_ATTRIBUTE_ATTACK)) {
                return getIntAttr(ITEM_ATTRIBUTE_ATTACK);
            }
            return items[id].attack;
        }
        int32_t getAttackSpeed() const {
            if (hasAttribute(ITEM_ATTRIBUTE_ATTACKSPEED)) {
                return getIntAttr(ITEM_ATTRIBUTE_ATTACKSPEED);
            }
            return items[id].attackSpeed;
        }
Code:
    ATTR_ATTACK = 28,
    ATTR_DEFENSE = 29,
    ATTR_EXTRADEFENSE = 30,
    ATTR_ARMOR = 31,
    ATTR_HITCHANCE = 32,
    ATTR_SHOOTRANGE = 33,
    ATTR_ATTACKSPEED = 34,

enums.h:
Code:
    ITEM_ATTRIBUTE_ATTACK = 1 << 10,
    ITEM_ATTRIBUTE_DEFENSE = 1 << 11,
    ITEM_ATTRIBUTE_EXTRADEFENSE = 1 << 12,
    ITEM_ATTRIBUTE_ARMOR = 1 << 13,
    ITEM_ATTRIBUTE_HITCHANCE = 1 << 14,
    ITEM_ATTRIBUTE_SHOOTRANGE = 1 << 15,
    ITEM_ATTRIBUTE_OWNER = 1 << 16,
    ITEM_ATTRIBUTE_DURATION = 1 << 17,
    ITEM_ATTRIBUTE_DECAYSTATE = 1 << 18,
    ITEM_ATTRIBUTE_CORPSEOWNER = 1 << 19,
    ITEM_ATTRIBUTE_CHARGES = 1 << 20,
    ITEM_ATTRIBUTE_FLUIDTYPE = 1 << 21,
    ITEM_ATTRIBUTE_DOORID = 1 << 22,
    ITEM_ATTRIBUTE_ATTACKSPEED = 1 << 23,

items.h:
Code:
        int32_t attack;
        int32_t defense;
        int32_t extraDefense;
        int32_t armor;
        int32_t rotateTo;
        int32_t runeMagLevel;
        int32_t runeLevel;
        int32_t attackSpeed;
sorry if this is hard to understand, basically i added attackspeed everywhere i could find that had to do with item attack
 
Last edited:
Solution
@Cornwallis, Your code is definitely correct, I'd recompile again and make sure you are using the correct executable to start the server.

i think its case sensitive so try to change the lines in items.xml from
Code:
        <attribute key="attackspeed" value="500" />
to
Code:
<attribute key="attackSpeed" value="500" />

if it didn't work try to change in your items.cpp to

Code:
        } else if (tmpStrValue == "attack") {
            it.attack = pugi::cast<int32_t>(valueAttribute.value());
        } else if (tmpStrValue == "attackSpeed") {
            it.attackSpeed = pugi::cast<int32_t>(valueAttribute.value());
That would make it not work completely, the tmpStrValue is lowered, so any capital letters when comparing...
i think its case sensitive so try to change the lines in items.xml from
Code:
        <attribute key="attackspeed" value="500" />
to
Code:
<attribute key="attackSpeed" value="500" />

if it didn't work try to change in your items.cpp to

Code:
        } else if (tmpStrValue == "attack") {
            it.attack = pugi::cast<int32_t>(valueAttribute.value());
        } else if (tmpStrValue == "attackSpeed") {
            it.attackSpeed = pugi::cast<int32_t>(valueAttribute.value());
 
@Cornwallis, Your code is definitely correct, I'd recompile again and make sure you are using the correct executable to start the server.

i think its case sensitive so try to change the lines in items.xml from
Code:
        <attribute key="attackspeed" value="500" />
to
Code:
<attribute key="attackSpeed" value="500" />

if it didn't work try to change in your items.cpp to

Code:
        } else if (tmpStrValue == "attack") {
            it.attack = pugi::cast<int32_t>(valueAttribute.value());
        } else if (tmpStrValue == "attackSpeed") {
            it.attackSpeed = pugi::cast<int32_t>(valueAttribute.value());
That would make it not work completely, the tmpStrValue is lowered, so any capital letters when comparing tmpStrValue will always fail.
 
Solution
oh shit, so I used what both of you said, and made the line in items.cpp:
Code:
        } else if (tmpStrValue == "attackspeed") {
            it.attackSpeed = pugi::cast<int32_t>(valueAttribute.value());
and did attackspeed = 500 in items.xml, and it works. Thank you guys!
 
I followed the steps from @Cornwallis, @Infernum and @Shadow_ from this thread, and @kor (Attack Damage/Attack Speed on Bow/Crossbow (https://otland.net/threads/attack-damage-attack-speed-on-bow-crossbow.187940/page-2#post-2526193)) and could make it work changing player.h:

C++:
        uint32_t getAttackSpeed() const {
            Item* weapon = getWeapon(false);

            if (weapon && weapon->getAttackSpeed() > 0)
                return weapon->getAttackSpeed();
            return vocation->getAttackSpeed();
        }

All credits go to them. I just copied and pasted basically.
 
Last edited:
Hi, i want install attack speed on my serv tfs 1.3 and i dont know where you put this

Code:
ItemType::ItemType() :
group(ITEM_GROUP_NONE), type(ITEM_TYPE_NONE), id(0), clientId(0),
stackable(false), isAnimation(false), weight(0), levelDoor(0), decayTime(0),
wieldInfo(0), minReqLevel(0), minReqMagicLevel(0), charges(0), maxHitChance(-1),
decayTo(-1), attack(0), attackSpeed(0), defense(0), extraDefense(0), armor(0), rotateTo(0),
runeMagLevel(0), runeLevel(0), combatType(COMBAT_NONE), transformToOnUse(),
transformToFree(0), destroyTo(0), maxTextLen(0), writeOnceItemId(0),
transformEquipTo(0), transformDeEquipTo(0), maxItems(8), slotPosition(SLOTP_HAND),
speed(0), wareId(0), magicEffect(CONST_ME_NONE), bedPartnerDir(DIRECTION_NONE),
weaponType(WEAPON_NONE), ammoType(AMMO_NONE), shootType(CONST_ANI_NONE),
corpseType(RACE_NONE), fluidSource(FLUID_NONE), floorChange(0),
alwaysOnTopOrder(0), lightLevel(0), lightColor(0), shootRange(1), hitChance(0),
forceUse(false), hasHeight(false), walkStack(true), blockSolid(false),
blockPickupable(false), blockProjectile(false), blockPathFind(false),
allowPickupable(false), showDuration(false), showCharges(false),
showAttributes(false), replaceable(true), pickupable(false), rotatable(false),
useable(false), moveable(false), alwaysOnTop(false), canReadText(false),
canWriteText(false), isVertical(false), isHorizontal(false), isHangable(false),
allowDistRead(false), lookThrough(false), stopTime(false), showCount(true)
 
Hello nefinoo. Please create your own thread in Support, about your specific problem.
Locking this thread since the OP's issue is solved.
 
Status
Not open for further replies.
Back
Top