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

Feature [TFS 1.2] Reflection attribute

Infernum

Senator
Joined
Feb 14, 2015
Messages
5,643
Solutions
559
Reaction score
3,948
enums.h

under the last attribute in itemAttrTypes (ITEM_ATTRIBUTE_DOORID = 1 << 22, if you haven't edited it, and use the number after << + 1 for reflection)
C++:
ITEM_ATTRIBUTE_REFLECTION = 1 << 23,

under ORIGIN_RANGED in CombatOrigin
C++:
ORIGIN_REFLECT,

item.h

in:
C++:
inline static bool isIntAttrType
take the hex value (default is 0x7FFE13) and use bitwise or ( | ) with (1 << 23) and replace the hex with the new value you get (you can do this at Lua: demo) with this code:
Lua:
print(string.format("0x%x", 0x7FFE13 | (1 << 23)))
you should now get 0xFFFE13, replace the value in isIntAttrType with the new hex value we have

under int8_t getHitChance, put:
C++:
        int32_t getReflection() const {
            if (hasAttribute(ITEM_ATTRIBUTE_REFLECTION)) {
                return getIntAttr(ITEM_ATTRIBUTE_REFLECTION);
            }
            return items[id].reflection;
        }

item.cpp

find this code:
C++:
            int32_t attack, defense, extraDefense;
            if (item) {
                attack = item->getAttack();
                defense = item->getDefense();
                extraDefense = item->getExtraDefense();
            } else {
                attack = it.attack;
                defense = it.defense;
                extraDefense = it.extraDefense;
            }
replace it with:
C++:
            int32_t attack, defense, extraDefense, reflection;
            if (item) {
                attack = item->getAttack();
                defense = item->getDefense();
                extraDefense = item->getExtraDefense();
                reflection = item->getReflection();
            } else {
                attack = it.attack;
                defense = it.defense;
                extraDefense = it.extraDefense;
                reflection = it.reflection;
            }

find this piece of code (should be around line 896)
C++:
            if (defense != 0 || extraDefense != 0) {
                if (begin) {
                    begin = false;
                    s << " (";
                } else {
                    s << ", ";
                }

                s << "Def:" << defense;
                if (extraDefense != 0) {
                    s << ' ' << std::showpos << extraDefense << std::noshowpos;
                }
            }
and put this below the code above
C++:
            if (reflection != 0) {
                if (begin) {
                    begin = false;
                    s << " (";
                } else {
                    s << ", ";
                }
               
                s << "Reflection: " << reflection << std::noshowpos << "%";

            }


items.h

under
C++:
int32_t defense = 0;
put
C++:
int32_t reflection = 0;

items.cpp

find:
C++:
        } else if (tmpStrValue == "defense") {
            it.defense = pugi::cast<int32_t>(valueAttribute.value());
put this under it:
C++:
        } else if (tmpStrValue == "reflect") {
            it.reflection = pugi::cast<int32_t>(valueAttribute.value());

player.h

under
C++:
int32_t getArmor() const final;
put
C++:
int32_t getReflection() const;

player.cpp

under:
C++:
int32_t Player::getArmor() const
{
    int32_t armor = 0;

    static const slots_t armorSlots[] = {CONST_SLOT_HEAD, CONST_SLOT_NECKLACE, CONST_SLOT_ARMOR, CONST_SLOT_LEGS, CONST_SLOT_FEET, CONST_SLOT_RING};
    for (slots_t slot : armorSlots) {
        Item* inventoryItem = inventory[slot];
        if (inventoryItem) {
            armor += inventoryItem->getArmor();
        }
    }
    return static_cast<int32_t>(armor * vocation->armorMultiplier);
}

put:
C++:
int32_t Player::getReflection() const
{
    int32_t reflection = 0;

    static const slots_t armorSlots[] = { CONST_SLOT_HEAD, CONST_SLOT_NECKLACE, CONST_SLOT_ARMOR, CONST_SLOT_LEGS, CONST_SLOT_FEET, CONST_SLOT_RING, CONST_SLOT_LEFT, CONST_SLOT_RIGHT };
    for (slots_t slot : armorSlots) {
        Item* inventoryItem = inventory[slot];
        if (inventoryItem) {
            reflection += inventoryItem->getReflection();
        }
    }
    return reflection;
}

game.cpp

inside of
C++:
bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage)
under:
C++:
target->drainMana(attacker, manaDamage);
put:
C++:
                // mana reflect
                if (targetPlayer && damage.origin != ORIGIN_REFLECT) {
                    int32_t reflection = targetPlayer->getReflection();
                    if (reflection != 0) {
                        CombatDamage reflectDamage;
                        reflectDamage.primary.value = static_cast<int32_t>(-damage.primary.value * (reflection / 100.0));
                        reflectDamage.secondary.value = static_cast<int32_t>(-damage.secondary.value * (reflection / 100.0));
                        reflectDamage.primary.type = damage.primary.type;
                        reflectDamage.secondary.type = damage.secondary.type;
                        reflectDamage.origin = ORIGIN_REFLECT; // create a new origin ORIGIN_REFLECT to avoid infinite reflection between 2 players
                        combatChangeHealth(target, attacker, reflectDamage);
                    }
                }

under: target->drainHealth(attacker, realDamage);
put:
C++:
        // reflect health
        if (targetPlayer && damage.origin != ORIGIN_REFLECT) {
            int32_t reflection = targetPlayer->getReflection();
            if (reflection != 0) {
                CombatDamage reflectDamage;
                reflectDamage.primary.value = static_cast<int32_t>(-damage.primary.value * (reflection / 100.0));
                reflectDamage.secondary.value = static_cast<int32_t>(-damage.secondary.value * (reflection / 100.0));
                reflectDamage.primary.type = damage.primary.type;
                reflectDamage.secondary.type = damage.secondary.type;
                reflectDamage.origin = ORIGIN_REFLECT;
                combatChangeHealth(target, attacker, reflectDamage);
            }
        }



the rest of the code is for scripting purposes, so this isn't 100% necessary if you aren't planning on tampering with reflection using lua

luascript.h

under:
C++:
static int luaItemTypeGetArmor(lua_State* L);
put:
C++:
static int luaItemTypeGetReflection(lua_State* L);

luascript.cpp

under:
C++:
registerEnum(ITEM_ATTRIBUTE_DOORID)
put:
C++:
registerEnum(ITEM_ATTRIBUTE_REFLECTION)

under:
C++:
registerEnum(ORIGIN_RANGED)
put:
C++:
registerEnum(ORIGIN_REFLECT)

under:
C++:
registerMethod("ItemType", "getArmor", LuaScriptInterface::luaItemTypeGetArmor);
put:
C++:
registerMethod("ItemType", "getReflection", LuaScriptInterface::luaItemTypeGetReflection);

under:
C++:
int LuaScriptInterface::luaItemTypeGetArmor(lua_State* L)
{
    // itemType:getArmor()
    const ItemType* itemType = getUserdata<const ItemType>(L, 1);
    if (itemType) {
        lua_pushnumber(L, itemType->armor);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

put:
C++:
int LuaScriptInterface::luaItemTypeGetReflection(lua_State* L)
{
    // itemType:getReflection()
    const ItemType* itemType = getUserdata<const ItemType>(L, -1);
    if (itemType) {
        lua_pushnumber(L, itemType->reflection);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

now you can use ITEM_ATTRIBUTE_REFLECTION, ORIGIN_REFLECT, and itemType:getReflection() in your scripts
you can set reflection inside of items.xml with:
XML:
<attribute key="reflect" value="10"/>
you can set reflection of items with lua using:
Lua:
item:setAttribute(ITEM_ATTRIBUTE_REFLECTION, 10)

also forgot, inside of game.cpp in bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage)
put
C++:
    if (!target) {
        return false;
    }
at the top of the function, otherwise it will crash when stepping on magic fields that damage you
 
Last edited by a moderator:
Very nice release! I love that you included the full instructions to properly follow master-branch's coding protocols and standards as with the lua demo you have there :D That's awesome! Lots to learn from here
 
item.h

in:
C++:
inline static bool isIntAttrType
take the hex value (default is 0x7FFE13) and use bitwise or ( | ) with (1 << 23) and replace the hex with the new value you get (you can do this at Lua: demo) with this code:
Lua:
print(string.format("0x%x", 0x7FFE13 | (1 << 23)))
you should now get 0xFFFE13, replace the value in isIntAttrType with the new hex value we have

You my hero.
 
I did everything correctly, I inserted in the following script: CreatureEvent - [TFS 1.1] Random Item Stats
How can I know if it's working? Is there going to be some animation showing the monster taking damage when attacking me, or will it only subside?
Since I can not edit my comment, I'll say it right here.
I solved the problem, was that I noticed that by default, the item will always have 0 of reflect, so in the script I modified so that when it had 0, a base value was added
 
i left something out in this post and i haven't felt like fixing it cause i didn't think people would use this
but to make this feature work correctly you also need to serialize the attribute in Item::serializeAttr
C++:
    if (hasAttribute(ITEM_ATTRIBUTE_REFLECTION)) {
        propWriteStream.write<uint8_t>(ATTR_REFLECTION);
        propWriteStream.write<uint8_t>(getIntAttr(ITEM_ATTRIBUTE_REFLECTION));
    }
and you also need to read the serialized attribute when the item is loaded in Item::readAttr
C++:
        case ATTR_REFLECTION: {
            uint8_t reflection;
            if (!propStream.read<uint8_t>(reflection)) {
                return ATTR_READ_ERROR;
            }

            setIntAttr(ITEM_ATTRIBUTE_REFLECTION, reflection);
            break;
        }
 
i left something out in this post and i haven't felt like fixing it cause i didn't think people would use this
but to make this feature work correctly you also need to serialize the attribute in Item::serializeAttr
C++:
    if (hasAttribute(ITEM_ATTRIBUTE_REFLECTION)) {
        propWriteStream.write<uint8_t>(ATTR_REFLECTION);
        propWriteStream.write<uint8_t>(getIntAttr(ITEM_ATTRIBUTE_REFLECTION));
    }
and you also need to read the serialized attribute when the item is loaded in Item::readAttr
C++:
        case ATTR_REFLECTION: {
            uint8_t reflection;
            if (!propStream.read<uint8_t>(reflection)) {
                return ATTR_READ_ERROR;
            }

            setIntAttr(ITEM_ATTRIBUTE_REFLECTION, reflection);
            break;
        }
Error:
identifier "ATTR_REFLECTION" is undefined
 
@Vulcan_ Could you specify above which part I should put the fix for crashing when walking on fields causing damage with a reflection item equipped? Can't seem to get it work correctly..
 
Hi vulcan the reflection attribute works great, but i can get to work it to appear on description
Code:
if (reflection != 0) {
                if (begin) {
                    begin = false;
                    s << " (";
                } else {
                    s << ", ";
                }
              
                s << "Reflection: " << reflection << std::noshowpos << "%";
            }

thanks in advance
 
Hi vulcan the reflection attribute works great, but i can get to work it to appear on description
Code:
if (reflection != 0) {
                if (begin) {
                    begin = false;
                    s << " (";
                } else {
                    s << ", ";
                }
             
                s << "Reflection: " << reflection << std::noshowpos << "%";
            }

thanks in advance
you CAN or CANT ?
 
Back
Top