Feature [TFS 1.2] Reflection attribute

Stigma

Well-Known Member
Joined
Feb 14, 2015
Messages
4,363
Best answers
356
Likes
1,938
#1
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:
Joined
Dec 26, 2013
Messages
1,218
Best answers
4
Likes
370
#3
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
 

Peonso

Godly Member
Joined
Jan 14, 2008
Messages
1,451
Best answers
22
Likes
923
#12
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.
 
Joined
May 4, 2011
Messages
209
Best answers
1
Likes
23
#14
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
 

Stigma

Well-Known Member
Joined
Feb 14, 2015
Messages
4,363
Best answers
356
Likes
1,938
#15
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;
        }
 
Joined
May 4, 2011
Messages
209
Best answers
1
Likes
23
#16
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
 

Stigma

Well-Known Member
Joined
Feb 14, 2015
Messages
4,363
Best answers
356
Likes
1,938
#17
item.h
enum AttrTypes_t {
after ATTR_SHOOTRANGE = 33,
add ATTR_REFLECTION = 34,
 
Joined
Sep 30, 2009
Messages
45
Best answers
0
Likes
6
#18
@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..
 
Joined
Jul 5, 2013
Messages
33
Best answers
0
Likes
6
#19
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
 

Stigma

Well-Known Member
Joined
Feb 14, 2015
Messages
4,363
Best answers
356
Likes
1,938
#20
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 ?
 
Top