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

Weapons with advantage vs some monsters

Calder

New Member
Joined
Jul 21, 2019
Messages
21
Reaction score
4
Location
Chile
TFS 1.3.10
Hello, is there a chance that a weapon has increased damage against some monsters?

example an rl weapon:

Lua:
<item id="7402" article="a" name="dragon slayer">
        <attribute key="weight" value="8200" />
        <attribute key="defense" value="28" />
        <attribute key="attack" value="44" />
        <attribute key="weaponType" value="sword" />
        <attribute key="slotType" value="two-handed" />
        <attribute key="imbuingSlots" value="3" />
</item>

+ 100% dmg vs All Dragons

Should I add any script in movements.xml or weapons.xml?

Final version
In weapons.xml add item:


Lua:
<!-- dragon slayer -->
    <melee id="7402" level="70" unproperly="1" script="dragonslayer.lua" >
        <vocation name="Knight" />

    </melee>


dragonslayer.lua (in \data\weapons\scripts):

Lua:
-- Normal combat damage
local combat_normal = Combat()
combat_normal:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat_normal:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
combat_normal:setFormula(COMBAT_FORMULA_SKILL, 0, 0, 1, 0)  -- normal damage

-- Combat damage against dragons
local combat_dragons = Combat()
combat_dragons:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat_dragons:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
combat_dragons:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HITAREA)
combat_dragons:setFormula(COMBAT_FORMULA_SKILL, 0, 0, 2, 0)  -- damage x 2


-- On use weapon
function onUseWeapon(player, variant)
    local target = Monster(variant.number)
    -- Is target a monster
    if target and target:isMonster() then
        -- Does the target have "dragon" somewhere in the creature name
        if target:getName():lower():find("dragon") then
            -- Use combat_dragons combat object
            return combat_dragons:execute(player, variant)
        end
    end
    -- Use normal combat object
    return combat_normal:execute(player, variant)
end
 
Last edited:
Solution
Hmm, based on this:
C++:
void Weapon::internalUseWeapon(Player* player, Item* item, Creature* target, int32_t damageModifier) const
{
	if (scripted) {
		LuaVariant var;
		var.type = VARIANT_NUMBER;
		var.number = target->getID();
		executeUseWeapon(player, var);
	} else {
		CombatDamage damage;
		WeaponType_t weaponType = item->getWeaponType();
		if (weaponType == WEAPON_AMMO || weaponType == WEAPON_DISTANCE) {
			damage.origin = ORIGIN_RANGED;
		} else {
			damage.origin = ORIGIN_MELEE;
		}
		damage.primary.type = params.combatType;
		damage.primary.value = (getWeaponDamage(player, target, item) * damageModifier) / 100...
Register it to a script file in data/weapons

And in the script file, see if variant is a monster, if creature name contains dragon execute a different Combat object that has 30% more damage in the setFormula properties.
 
how could I do that script? if it's not too much trouble
I don't understand how "setFormula" works

Lua:
local combat = Combat()
    combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
    combat:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
    combat:setFormula(COMBAT_FORMULA_SKILL, 0, 0, 0, 0)

function onUseWeapon(player, variant)
     return combat:execute(player, variant)
end
 
Last edited:
I'm pretty lost here as well, I seem to be unable to find a way to retrieve the default "formula" in Lua, at a quick glance there seem to only be ways to set the formula, and the source code is pretty heavy to chew through, even for stuff such as finding the formula to replicate it in Lua.

Some people have solved this using onHealthChange etc as a creaturescript, which I find to be quite messy since you have to figure out which weapon the player is using and running weapon specific code in an unintended Lua scope location.

I also spotted a different, and probably more common approach, by overriding the formula in a callback:

Although the same problem persists, we still dont know the proper "default values" to use in the formula, and I think using this will override the formula in the sources.

but at least now the meaning behind the params are a bit more apparent. You might be able to do something along the lines of this:

(Grabbed formula from Brutal strike)

Lua:
-- Normal combat damage
local combat_normal = Combat()
combat_normal:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat_normal:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
function normal_onGetFormulaValues(player, skill, attack, factor)
    -- Formula to calculate min and max damage
    local min = (player:getLevel() / 5) + (skill * attack * 0.02) + 4
    local max = (player:getLevel() / 5) + (skill * attack * 0.04) + 9
    return -min, -max
end
combat_normal:setCallback(CALLBACK_PARAM_SKILLVALUE, "normal_onGetFormulaValues")

-- Combat damage against dragons
local combat_dragons = Combat()
combat_dragons:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat_dragons:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
function dragon_onGetFormulaValues(player, skill, attack, factor)
    local min = (player:getLevel() / 5) + (skill * attack * 0.02) + 4
    local max = (player:getLevel() / 5) + (skill * attack * 0.04) + 9
    -- Multiply return values by 1.25 for +25% damage.
    return -(min * 1.25), -(max * 1.25)
end
combat_dragons:setCallback(CALLBACK_PARAM_SKILLVALUE, "dragon_onGetFormulaValues")

-- On use weapon
function onUseWeapon(player, variant)
    local target = Monster(variant)
    -- Is target a monster?
    if target and target:isMonster() then
        -- Does the target have "dragon" somewhere in the creature name?
        if target:getName():lower():find("dragon") then
            -- Use combat_dragons combat object
            return combat_dragons:execute(player, variant)
        end
    end
    -- Use normal combat object
    return combat_normal:execute(player, variant)
end

In the onUseWeapon function we determine if the target is a dragon type monster (based on creature name), and that way determine which of the two combat objects (combat_normal, combat_dragons) we should execute when we use the weapon.
 
Last edited:
I have succeeded in combat_normal "setFormula", damage x 1 = 100%, but combat_dragons vs dragons is not working.
normal_combat is applied all the time.

Lua:
 -- Normal combat damage
local combat_normal = Combat()
combat_normal:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat_normal:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
combat_normal:setFormula(COMBAT_FORMULA_SKILL, 0, 0, 1, 0)

-- Combat damage against dragons
local combat_dragons = Combat()
combat_dragons:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat_dragons:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
combat_dragons:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HITAREA)
combat_dragons:setFormula(COMBAT_FORMULA_SKILL, 0, 0, 1.3, 0)


-- On use weapon
function onUseWeapon(player, variant)
    local target = Monster(variant)
    -- Is target a monster?
    if target and target:isMonster() then
        -- Does the target have "dragon" somewhere in the creature name?
        if target:getName():lower():find("dragon") then
            -- Use combat_dragons combat object
            return combat_dragons:execute(player, variant)
        end
    end
    -- Use normal combat object
    return combat_normal:execute(player, variant)
end
 
Hmm, based on this:
C++:
void Weapon::internalUseWeapon(Player* player, Item* item, Creature* target, int32_t damageModifier) const
{
	if (scripted) {
		LuaVariant var;
		var.type = VARIANT_NUMBER;
		var.number = target->getID();
		executeUseWeapon(player, var);
	} else {
		CombatDamage damage;
		WeaponType_t weaponType = item->getWeaponType();
		if (weaponType == WEAPON_AMMO || weaponType == WEAPON_DISTANCE) {
			damage.origin = ORIGIN_RANGED;
		} else {
			damage.origin = ORIGIN_MELEE;
		}
		damage.primary.type = params.combatType;
		damage.primary.value = (getWeaponDamage(player, target, item) * damageModifier) / 100;
		damage.secondary.type = getElementType();
		damage.secondary.value = getElementDamage(player, target, item);
		Combat::doCombatHealth(player, target, damage, params);
	}

	onUsedWeapon(player, item, target->getTile());
}

It appears var is an object with 2 properties, var.type and var.number, and this var object is being passed to the lua environment.
Try to replace
Lua:
local target = Monster(variant)

with:
Lua:
local target = Monster(variant.number)

Hopefully this will successfully initialize the target monster object in function onUseWeapon(player, variant)
 
Solution
wand or rod version:

Lua:
-- Normal combat damage
local combat_normal = Combat()
combat_normal:setParameter(COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE)  -- element
combat_normal:setParameter(COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_SMALLICE) -- projectile
combat_normal:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_ICEAREA)

function normal_onGetFormulaValues(player, level, maglevel)
    local min =  80
    local max =  110
    return -min, -max
end
combat_normal:setCallback(CALLBACK_PARAM_SKILLVALUE, "normal_onGetFormulaValues")

-- Combat damage against dragons
local combat_dragons = Combat()
combat_dragons:setParameter(COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE)  -- element
combat_dragons:setParameter(COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_SMALLICE)  -- projectile
combat_dragons:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HITAREA)

function dragon_onGetFormulaValues(player, level, maglevel)
    -- damage x 2
    local min = 80 * 2   
    local max = 110 * 2
    return -min, -max
end
combat_dragons:setCallback(CALLBACK_PARAM_SKILLVALUE, "dragon_onGetFormulaValues")


-- On use weapon
function onUseWeapon(player, variant)
    local target = Monster(variant.number)
    -- Is target a monster
    if target and target:isMonster() then
        -- Does the target have "dragon" somewhere in the creature name
        if target:getName():lower():find("dragon") then
            -- Use combat_dragons combat object
            return combat_dragons:execute(player, variant)
        end
    end
    -- Use normal combat object
    return combat_normal:execute(player, variant)
end
 
good but....can this be taken a step further?

lets propose that doing every monster would be taxing in one way or another and it should better serve us to do groups or races. Undead...subhumans...monsters or so forth, by at least some existing tagging? race tag may cover enough? Something to consider.
 
good but....can this be taken a step further?

lets propose that doing every monster would be taxing in one way or another and it should better serve us to do groups or races. Undead...subhumans...monsters or so forth, by at least some existing tagging? race tag may cover enough? Something to consider.

Maybe check out variant.type instead of variant.number
 
Back
Top