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

Adding attacked speed to weapon TFS 1.1

strutZ

Australian OT Member {AKA Beastn}
Joined
Nov 16, 2014
Messages
1,391
Solutions
7
Reaction score
550
Hi there otland,

Was just wondering if it is possible to add attack speed to a weapon only? if so how?

Regards,
Beastn.
 
@Breed, @beastn

There is no attack speed attribute in 1.1
The only attack speed you have at the moment is the one you set for the vocations in vocations.xml
Oh, I didn't know that >.<

Edit: I just checked, there is attack and then there is speed but no attack speed or attackspeed :(

I wrote a parser that helps me search names, id's or attributes :)
I love building tools :)
 
Last edited:
Well that sucks :'( Which source edits need to be made? Cant i just make them and re compile?
 
You can change anything in the source to whatever you want and compile, nobody is preventing you from doing that.
From immediate observations, here is the getter function for the attack speed of the player.
https://github.com/otland/forgottenserver/blob/master/src/player.h#L1354

As you can see, it only gets the attack speed value in vocations.xml. Nothing else is ever factored into the player's attack speed.
 
@Breed
You need to set, not get. Without editing the sources, you cannot set any attack speed anywhere.
There is however, a workaround. It's gonna be a bit more complex though, well maybe not, but in terms of formulas.

onUseWeapon is a script environment that you can use, which resides in the weapons folder.
onUseWeapon is called when a player uses a weapon during attack mode.

So, what you can do is put in addEvents() to execute combats in between the main intervals of attack speed.

Here is an example script of burst arrows:
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, 1)
setCombatParam(combat, COMBAT_PARAM_BLOCKSHIELD, 1)
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_EFFECT, CONST_ME_FIREAREA)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_BURSTARROW)
setCombatFormula(combat, COMBAT_FORMULA_SKILL, 1, 0, 1, 0)

local area = createCombatArea( { {1, 1, 1}, {1, 3, 1}, {1, 1, 1} } )
setCombatArea(combat, area)

function addCombat(cid, combat, var)
    local player = Player(cid)
    if not player then
        return false
    end
   
    if player:getTarget() == nil then
        return false
    end
   
    doCombat(player, combat, var)
end

function onUseWeapon(player, var)
    addEvent(addCombat, 1000, player, combat, var)
    return doCombat(player, combat, var)
end

You can see, I added the addCombat() function, which checks to see if the player still exists, checks to see if the player has not stopped attacking, then after all that, it will execute the combat. addCombat() was called in my addEvent() 1 second after the original attack. So, if my default attack speed is 2000 (2 seconds), with this, I can now attack every 1000 ms (1 second).
 
@Breed
You need to set, not get. Without editing the sources, you cannot set any attack speed anywhere.
There is however, a workaround. It's gonna be a bit more complex though, well maybe not, but in terms of formulas.

onUseWeapon is a script environment that you can use, which resides in the weapons folder.
onUseWeapon is called when a player uses a weapon during attack mode.

So, what you can do is put in addEvents() to execute combats in between the main intervals of attack speed.

Here is an example script of burst arrows:
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, 1)
setCombatParam(combat, COMBAT_PARAM_BLOCKSHIELD, 1)
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_EFFECT, CONST_ME_FIREAREA)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_BURSTARROW)
setCombatFormula(combat, COMBAT_FORMULA_SKILL, 1, 0, 1, 0)

local area = createCombatArea( { {1, 1, 1}, {1, 3, 1}, {1, 1, 1} } )
setCombatArea(combat, area)

function addCombat(cid, combat, var)
    local player = Player(cid)
    if not player then
        return false
    end
  
    if player:getTarget() == nil then
        return false
    end
  
    doCombat(player, combat, var)
end

function onUseWeapon(player, var)
    addEvent(addCombat, 1000, player, combat, var)
    return doCombat(player, combat, var)
end

You can see, I added the addCombat() function, which checks to see if the player still exists, checks to see if the player has not stopped attacking, then after all that, it will execute the combat. addCombat() was called in my addEvent() 1 second after the original attack. So, if my default attack speed is 2000 (2 seconds), with this, I can now attack every 1000 ms (1 second).

Oh wow i'll give it a try and let you know
 
Yeah, I'm assuming you can just add script tags to all the weapons in weapons.xml and make them use a single script.
For example, fire sword:
Code:
<melee id="2392" level="30" unproperly="1" script="weapon.lua"/>

There, I'm making the fire sword to use a script (like the one below).
I've tested it, it all works fine. It will do 1000 ms intervals of damage, instead of the default 2000.

Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, 1)
setCombatParam(combat, COMBAT_PARAM_BLOCKSHIELD, 1)
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatFormula(combat, COMBAT_FORMULA_SKILL, 1, 0, 1, 0)

function addCombat(cid, combat, var)
    local player = Player(cid)
    if not player then
        return false
    end
   
    if player:getTarget() == nil then
        return false
    end
   
    doCombat(player, combat, var)
end

function onUseWeapon(player, var)
    addEvent(addCombat, 1000, player, combat, var)
    return doCombat(player, combat, var)
end

All good :)
 
Yeah, I'm assuming you can just add script tags to all the weapons in weapons.xml and make them use a single script.
For example, fire sword:
Code:
<melee id="2392" level="30" unproperly="1" script="weapon.lua"/>

There, I'm making the fire sword to use a script (like the one below).
I've tested it, it all works fine. It will do 1000 ms intervals of damage, instead of the default 2000.

Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, 1)
setCombatParam(combat, COMBAT_PARAM_BLOCKSHIELD, 1)
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatFormula(combat, COMBAT_FORMULA_SKILL, 1, 0, 1, 0)

function addCombat(cid, combat, var)
    local player = Player(cid)
    if not player then
        return false
    end
  
    if player:getTarget() == nil then
        return false
    end
  
    doCombat(player, combat, var)
end

function onUseWeapon(player, var)
    addEvent(addCombat, 1000, player, combat, var)
    return doCombat(player, combat, var)
end

All good :)


HAHAHA you are the man!!! I love how you were saying it wasnt possible 5 mins ago... So if i want to slow it down which numbers would i change? coz lowering

Code:
    addEvent(addCombat, 1000, player, combat, var)

slows it but its hitting twice.
 
Oh, lowering the attack speed? Oooh didn't think of that.
You could just do an os.time check to determine when the last approved hit was.

So, for example, let's say I want a weapon to do 6000 ms attack speed, instead of 2000 ms.
When you start attacking, you want to set a player storage to store the os.time.
Using this value, you can check to see if os.time is >= the player storage value + 6 seconds.
If this is good, then doCombat, else just return false.

I can write an example after I finish dinner.
 
Thanks man would be helpful... Its always easier to understand seeing the code ;)
 
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, 1)
setCombatParam(combat, COMBAT_PARAM_BLOCKSHIELD, 1)
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatFormula(combat, COMBAT_FORMULA_SKILL, 1, 0, 1, 0)

function onUseWeapon(player, var)
    local PLAYER_HIT_TIME_LAST = 24000
    local speedInSeconds = 6
   
    if os.time() >= player:getStorageValue(PLAYER_HIT_TIME_LAST) + speedInSeconds then
        player:setStorageValue(PLAYER_HIT_TIME_LAST, os.time())
        return doCombat(player, combat, var)
    end
   
    return false
end
 
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, 1)
setCombatParam(combat, COMBAT_PARAM_BLOCKSHIELD, 1)
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatFormula(combat, COMBAT_FORMULA_SKILL, 1, 0, 1, 0)

function onUseWeapon(player, var)
    local PLAYER_HIT_TIME_LAST = 24000
    local speedInSeconds = 6
  
    if os.time() >= player:getStorageValue(PLAYER_HIT_TIME_LAST) + speedInSeconds then
        player:setStorageValue(PLAYER_HIT_TIME_LAST, os.time())
        return doCombat(player, combat, var)
    end
  
    return false
end

It works man but i cant make it any faster then 1 hit per 2 seconds Do you mind explaining the intervals?
 
You need to do more than one combat between onUseWeapon calls.
You also need to even it out that way it'd look realistic.

If you want 1 extra hit in between the onUseWeapon calls, you need to divide 2000 ms by 2 (first hit + the extra hit), which gets you 1000.
But if you want to add 2 extra hits in between onUseWeapon calls, you need to divide 2000 ms by 3 (first hit + 2 extra hits), which gets you approximately 667.
So, to do this one, you need to do doCombat twice, at 667 ms intervals.

Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, 1)
setCombatParam(combat, COMBAT_PARAM_BLOCKSHIELD, 1)
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatFormula(combat, COMBAT_FORMULA_SKILL, 1, 0, 1, 0)

function addCombat(cid, combat, var, interval, i)
    if i <= 0 then
        return false
    end

    local player = Player(cid)
    if not player then
        return false
    end
   
    if player:getTarget() == nil then
        return false
    end
   
    doCombat(player, combat, var)
   
    addEvent(addCombat, interval, player:getId(), interval, i - 1)
end

function onUseWeapon(player, var)
    local hitsInBetween = 2 -- You can just change this
    local interval = math.floor(2000 / hitsInBetween + 1)

    addEvent(addCombat, interval, player, combat, var, interval, hitsInBetween)
    return doCombat(player, combat, var)
end
 
Back
Top Bottom