Leo32
Getting back into it...
- Joined
- Sep 21, 2007
- Messages
- 987
- Solutions
- 14
- Reaction score
- 532
Edit: Fked the title again
This is a replacement for exori ico on my server.
It's basically the brutal strike spell, except;
Thrusting/spear/lance-type weapons use a different area altogether and do 150% damage on their two-handed types due to the smaller area.
CONST_ME_BLOCKHIT on walls for cool points
spells.xml
custom/brutal swing.lua
You will also needs to add the spell matrix rotate functions to the spells lib, or at the top of the brutal swing script, or in global.lua etc
spells/lib/spells.lua
add to the end:
Optional:
Because of how casterTargetOrDirection="1" works, you can't cast the spell if you have a target - and the the target isn't in sight: (RETURNVALUE_CREATUREISNOTREACHABLE).
This is fine in most scenarios, but I just didn't like it when it happened (creature targeted, behind a wall).
So I forced the spell to execute - by creating a new spell parameter/attribute alwaysUse.
spells.h
under:
add:
spells.cpp
under:
add:
replace:
with:
add alwaysUse="1" to your Brutal Swing Spell.
*Don't do this if you've customized this into a ranged spell.
spells.xml
This is a replacement for exori ico on my server.
It's basically the brutal strike spell, except;
- you can lock on to targets when you're in range
- it changes the hit area if the targeted monster is diagonal to you.
Thrusting/spear/lance-type weapons use a different area altogether and do 150% damage on their two-handed types due to the smaller area.
CONST_ME_BLOCKHIT on walls for cool points
spells.xml
XML:
<instant group="attack" name="Brutal Swing" words="brutal swing" lvl="15" mana="30" prem="1" needweapon="1" casterTargetOrDirection="1" exhaustion="6000" groupcooldown="2000" script="custom/brutal swing.lua">
<vocation name="..." />
</instant>
custom/brutal swing.lua
Lua:
local checkWeaponSlots = {
CONST_SLOT_LEFT,
CONST_SLOT_RIGHT,
}
-- These weapons have a different hit area
local lanceWeapons = { -- LANCE (3)
2414, -- Dragon Lance
2964, -- Ripper Lance
11323,-- Zaoan Halberd
13838,-- Heavy Trident
2425, -- Obsidian Lance
2426, -- Naginata
2438, -- Epee
2396, -- Ice Rapier
20093 -- Life Preserver
}
local hitArea = {
{ -- ONE HAND (1)
{ -- NESW
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 1, 3, 1, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
},
{ -- DIAGONAL
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 3, 1, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 0}
}
},
{ -- TWO HAND (2)
{ -- NESW
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 1, 3, 1, 0},
{0, 1, 0, 1, 0},
{0, 0, 0, 0, 0}
},
{ -- DIAGONAL
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 3, 1, 1},
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0}
}
},
{ -- LANCE (3)
{ -- NESW
{0, 1, 0},
{1, 1, 1},
{1, 3, 1}
},
{ -- DIAGONAL
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 3, 1},
{0, 0, 1, 0}
}
}
}
local combats = {}
function onGetFormulaValues(player, skill, attack, factor)
local skillTotal = skill * attack
local levelTotal = player:getLevel() / 5
return -(((skillTotal * 0.03) + 7) + (levelTotal)), -(((skillTotal * 0.05) + 11) + (levelTotal))
end
for i = 1, #hitArea do
combats[i] = Combat()
combats[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combats[i]:setParameter(COMBAT_PARAM_BLOCKARMOR, 1)
combats[i]:setParameter(COMBAT_PARAM_USECHARGES, 1)
combats[i]:setArea(createCombatArea(hitArea[i][1], hitArea[i][2]))
--combats[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_POFF)
end
local function animation(pos, playerpos)
if not Tile(Position(pos)):hasProperty(CONST_PROP_BLOCKPROJECTILE) then
--if Position(pos):isSightClear(playerpos) then
Position(pos):sendMagicEffect(CONST_ME_HITAREA)
--end
else
Position(pos):sendMagicEffect(CONST_ME_BLOCKHIT)
end
return true
end
function onCastSpell(creature, var)
local animationArea = { -- The start of each frame needs to have a 2 or 3 in it to indicate the player/target position
{ -- NOT DIAGONAL DIRECTION_NORTH / DIRECTION_EAST / DIRECTION_SOUTH / DIRECTION_WEST
{ -- ONE HAND
{ -- SWING (R to L)
{
{0, 2, 1},
},
{
{0, 1, 0},
},
{
{1, 0, 0},
}
},
{ -- SWING (L to R)
{
{1, 2, 0},
},
{
{0, 1, 0},
},
{
{0, 0, 1},
}
}
},
{ -- TWO HAND
{ -- SWING (R to L)
{
{0, 2, 0},
{0, 0, 1}
},
{
{0, 0, 1},
{0, 0, 0}
},
{
{0, 1, 0},
{0, 0, 0}
},
{
{1, 0, 0},
{0, 0, 0}
},
{
{0, 0, 0},
{1, 0, 0}
}
},
{ -- SWING (L to R)
{
{0, 2, 0},
{1, 0, 0}
},
{
{1, 0, 0},
{0, 0, 0}
},
{
{0, 1, 0},
{0, 0, 0}
},
{
{0, 0, 1},
{0, 0, 0}
},
{
{0, 0, 0},
{0, 0, 1}
}
}
},
{ -- LANCE
{ -- SWING (Only 1 direction)
{
{0, 0, 0},
{0, 0, 0},
{1, 2, 1}
},
{
{0, 0, 0},
{0, 0, 0},
{0, 1, 0}
},
{
{0, 0, 0},
{0, 1, 0},
{0, 0, 0}
},
{
{0, 1, 0},
{1, 0, 1},
{0, 0, 0}
}
}
}
},
{ -- DIAGONAL DIRECTION_NORTHWEST / DIRECTION_NORTHEAST / DIRECTION_SOUTHEST / DIRECTION_SOUTHWEST
{ -- ONE HAND
{ -- SWING (R to L)
{
{0, 0, 0},
{0, 2, 1},
{0, 0, 0}
},
{
{0, 0, 0},
{0, 1, 0},
{0, 0, 0}
},
{
{0, 0, 0},
{0, 0, 0},
{0, 1, 0}
}
},
{ -- SWING (L to R)
{
{0, 0, 0},
{0, 2, 0},
{0, 1, 0}
},
{
{0, 0, 0},
{0, 1, 0},
{0, 0, 0}
},
{
{0, 0, 0},
{0, 0, 1},
{0, 0, 0}
}
}
},
{ -- TWO HAND
{ -- SWING (R to L)
{
{0, 0, 2, 0, 1},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 0, 1, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 0, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 1, 0, 0}
}
},
{ -- SWING (L to R)
{
{0, 0, 2, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 1, 0, 0}
},
{
{0, 0, 0, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 0, 1, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 0, 0, 1},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
}
}
},
{ -- LANCE
{ -- SWING (Only 1 direction)
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 2, 1},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 0}
},
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 1, 0, 0},
{0, 0, 0, 0}
},
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
}
}
}
}
}
-- Defaults
local animationType = 1 -- Default (straight or diagonal)
local player = Player(creature)
local target = player:getTarget()
local creaturePos = creature:getPosition()
local direction = creature:getDirection()
local damageModifer = 1 -- Default (varies for special animations)
local weapon = 0
local attack = 0
local skill = 0
local swing = 1 -- Default (animation variants)
local directionalX = 0
local directionalY = 0
local range = 1
local distance = 0
local delay = 60 -- Time between animations in ms
-- Get config spell based on weapon
for i = 1,#checkWeaponSlots do -- Check what weapon is being used
if player:getSlotItem(checkWeaponSlots[i]) ~= nil then
local weaponLiteral = player:getSlotItem(checkWeaponSlots[i]) -- weapon object
local itemType = ItemType(weaponLiteral:getId()) -- itemtype object
local weaponType = itemType:getWeaponType()
if weaponType > 0 then
if isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE}, weaponType) then
-- Get weapon info
attack = itemType:getAttack()
if weaponLiteral:getAttribute(ITEM_ATTRIBUTE_ATTACK) > attack then -- If custom item with added attack
attack = weaponLiteral:getAttribute(ITEM_ATTRIBUTE_ATTACK)
end
-- Get skill to check
if weaponType == WEAPON_SWORD then
skill = player:getSkillLevel(SKILL_SWORD)
elseif weaponType == WEAPON_AXE then
skill = player:getSkillLevel(SKILL_AXE)
elseif weaponType == WEAPON_CLUB then
skill = player:getSkillLevel(SKILL_CLUB)
end
-- Determine animation based on weapontype
local positionType = itemType:getSlotPosition() -- How many hands
if positionType == 48 then -- ONE
weapon = 1 -- animation(1)
elseif positionType == 2096 then -- TWO
weapon = 2 -- animation(2)
end
if isInArray(lanceWeapons, itemType:getId()) then
weapon = 3 -- animation(3)
if positionType == 2096 then -- Two handed lances get extra damage because of smaller area
damageModifer = 1.5
end
end
-- If normal ONE or TWO hander, roll a swing direction
if weapon < 3 then
swing = math.random(1,2)
end
-- Creature targeted
if target then -- Make sure its in range before doing targeted changes
distance = creaturePos:getDistance(target:getPosition())
if distance <= range then
creaturePos = target:getPosition() -- Change position to monster
local playerPos = player:getPosition() -- Get player position
local diagonal = false
-- Adjust DIRECTION based on target location rather than player direction
if creaturePos.x > playerPos.x then
if creaturePos.y > playerPos.y then
direction = DIRECTION_SOUTHEAST
diagonal = true
elseif creaturePos.y < playerPos.y then
direction = DIRECTION_NORTHEAST
diagonal = true
elseif creaturePos.y == playerPos.y then
direction = DIRECTION_EAST
end
elseif creaturePos.x < playerPos.x then
if creaturePos.y > playerPos.y then
direction = DIRECTION_SOUTHWEST
diagonal = true
elseif creaturePos.y < playerPos.y then
direction = DIRECTION_NORTHWEST
diagonal = true
elseif creaturePos.y == playerPos.y then
direction = DIRECTION_WEST
end
elseif creaturePos.x == playerPos.x then
if creaturePos.y > playerPos.y then
direction = DIRECTION_SOUTH
else
direction = DIRECTION_NORTH
end
end
if diagonal then
animationType = 2
end
else -- Targeted, but not in range
target = false
local nextPos = player:getPosition():getNextPosition(player:getDirection(), 1)
if Tile(nextPos):hasProperty(CONST_PROP_BLOCKPROJECTILE) then -- If directional tile is not valid
creature:sendCancelMessage(RETURNVALUE_NOTENOUGHROOM)
creaturePos:sendMagicEffect(CONST_ME_POFF)
return false
else
var = Variant(nextPos) -- Change spell cast position back to directional pos and continue with spell
end
end
end
-- Rotate area based on DIRECTION
for i = 1, #animationArea[animationType][weapon][swing] do
if direction == DIRECTION_EAST or direction == DIRECTION_NORTHEAST then
animationArea[animationType][weapon][swing][i] = rotate_CW_90(animationArea[animationType][weapon][swing][i])
if not target then
directionalX = 1
end
elseif direction == DIRECTION_SOUTH or direction == DIRECTION_SOUTHEAST then
animationArea[animationType][weapon][swing][i] = rotate_180(animationArea[animationType][weapon][swing][i])
if not target then
directionalY = 1
end
elseif direction == DIRECTION_WEST or direction == DIRECTION_SOUTHWEST then
animationArea[animationType][weapon][swing][i] = rotate_CCW_90(animationArea[animationType][weapon][swing][i])
if not target then
directionalX = -1
end
else
if not target then
directionalY = -1
end
end
end
end
end
end
end
-- No weapon
if weapon == 0 then
creature:sendCancelMessage("You need to have a weapon equipped to use this spell.")
creaturePos:sendMagicEffect(CONST_ME_POFF)
return false
end
-- Damage formula
local skillTotal = skill * attack
local levelTotal = player:getLevel() / 5
local min, max = -(((skillTotal * 0.02) + 4) + (levelTotal) * damageModifer), -(((skillTotal * 0.04) + 9) + (levelTotal) * damageModifer)
combats[weapon]:setFormula(COMBAT_FORMULA_SKILL, 0, min, 0, max)
-- Collate animation
local centre = {}
local damagearea = {}
for j = 1, #animationArea[animationType][weapon][swing] do
for k,v in ipairs(animationArea[animationType][weapon][swing][j]) do
for i = 1, #v do
if v[i] == 3 or v[i] == 2 then
centre.Row = k
centre.Column = i
if v[i] == 3 then
table.insert(damagearea, centre)
end
elseif v[i] == 1 then
local darea = {}
darea.Row = k
darea.Column = i
darea.Delay = j * delay
table.insert(damagearea, darea)
end
end
end --print(centre.Column .. "," .. centre.Row)
end
-- Do Animation
for i = 1,#damagearea do
local damagepos = Position(creaturePos)
-- Compare with centrepos
local modifierx = damagearea[i].Column - centre.Column
local modifiery = damagearea[i].Row - centre.Row -- print(damagearea[i].Column .. "," .. damagearea[i].Row)
-- Adjust pos, account for direction
damagepos.x = damagepos.x + modifierx + directionalX -- print("x " .. modifierx .. " " .. "y " .. modifiery)
damagepos.y = damagepos.y + modifiery + directionalY -- print("Damage: " .. damagepos.x .. "," .. damagepos.y .. "," .. damagepos.z)
-- Animate
local animationDelay = damagearea[i].Delay or 0
addEvent(animation, animationDelay, damagepos) -- player:getPosition()
end
-- Execute Damage
combats[weapon]:execute(creature, var)
return true
end
You will also needs to add the spell matrix rotate functions to the spells lib, or at the top of the brutal swing script, or in global.lua etc
spells/lib/spells.lua
add to the end:
Lua:
function rotate_CCW_90(m)
local rotated = {}
for c, m_1_c in ipairs(m[1]) do
local col = {m_1_c}
for r = 2, #m do
col[r] = m[r][c]
end
table.insert(rotated, 1, col)
end
return rotated
end
function rotate_180(m)
return rotate_CCW_90(rotate_CCW_90(m))
end
function rotate_CW_90(m)
return rotate_CCW_90(rotate_CCW_90(rotate_CCW_90(m)))
end
ā Don't do if you're using this to make a ranged spell as it will go through walls.
Optional:
Because of how casterTargetOrDirection="1" works, you can't cast the spell if you have a target - and the the target isn't in sight: (RETURNVALUE_CREATUREISNOTREACHABLE).
This is fine in most scenarios, but I just didn't like it when it happened (creature targeted, behind a wall).
So I forced the spell to execute - by creating a new spell parameter/attribute alwaysUse.
spells.h
under:
C++:
bool internalCastSpell(Creature* creature, const LuaVariant& var);
bool needDirection = false;
bool hasParam = false;
bool hasPlayerNameParam = false;
bool checkLineOfSight = true;
bool casterTargetOrDirection = false;
C++:
bool alwaysUse = false;
spells.cpp
under:
C++:
if ((attr = node.attribute("direction"))) {
needDirection = attr.as_bool();
} else if ((attr = node.attribute("casterTargetOrDirection"))) {
casterTargetOrDirection = attr.as_bool();
}
C++:
if ((attr = node.attribute("alwaysUse"))) {
alwaysUse = attr.as_bool();
}
C++:
if (!canThrowSpell(player, target)) {
player->sendCancelMessage(RETURNVALUE_CREATUREISNOTREACHABLE);
g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
return false;
}
C++:
if (!canThrowSpell(player, target)) {
if (!alwaysUse) {
player->sendCancelMessage(RETURNVALUE_CREATUREISNOTREACHABLE);
g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
return false;
}
}
add alwaysUse="1" to your Brutal Swing Spell.
*Don't do this if you've customized this into a ranged spell.
spells.xml
XML:
<instant group="attack" name="Brutal Swing" words="brutal swing" ... ... ... alwaysUse="1" ... ... ... script="custom/brutal swing.lua">
Last edited: