Leo32
Getting back into it...
- Joined
- Sep 21, 2007
- Messages
- 987
- Solutions
- 14
- Reaction score
- 532
This is a replacement for groundshaker on my OT.
It pushes monsters and players away from the caster.
If the target is stuck up against a wall, they are stunned and receive a high amount of damage.
You will need to add CONDITION_STUN your sources to use this spell.
Spell - [TFS 1.X] Shield Bash (https://otland.net/threads/tfs-1-x-shield-bash.268433/#post-2591129)
spells.xml
scripts/custom/shove.lua
Edit: Fixed this line
TBH this line should get the direction of the wall they're hitting, instead of assuming playerDir is right, improvement suggestion if you are using this spell
It pushes monsters and players away from the caster.
If the target is stuck up against a wall, they are stunned and receive a high amount of damage.
You will need to add CONDITION_STUN your sources to use this spell.
Spell - [TFS 1.X] Shield Bash (https://otland.net/threads/tfs-1-x-shield-bash.268433/#post-2591129)
spells.xml
XML:
<instant group="attack" name="Shove" words="shove" lvl="30" mana="200" exhaustion="6000" groupcooldown="2000" script="custom/shove.lua">
<vocation name="..." />
</instant>
scripts/custom/shove.lua
Lua:
-- Damaging Area
local hitArea = {
{1, 1, 1},
{1, 2, 1},
{1, 1, 1}
}
-- Animation Frames
local animationArea = {
{
{0, 0, 0, 0, 0},
{0, 0, 1, 0, 0},
{0, 1, 2, 1, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 0}
},
{
{0, 0, 0, 0, 0},
{0, 1, 0, 1, 0},
{0, 0, 0, 0, 0},
{0, 1, 0, 1, 0},
{0, 0, 0, 0, 0}
},
{
{0, 1, 1, 1, 0},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{0, 1, 1, 1, 0}
}
}
-- Get position behind target
function Position:getBehindPos(direction, steps)
local offset = Position.directionOffset[direction]
if offset then
steps = steps or 1
self.x = self.x + offset.x * steps
self.y = self.y + offset.y * steps
end
return self
end
-- For shuffling the secondaryPosition table
function shuffle(t)
local rand = math.random
assert(t, "table.shuffle() expected a table, got nil")
local iterations = #t
local j
for i = iterations, 2, -1 do
j = rand(i)
t[i], t[j] = t[j], t[i]
end
end
-- Get 8-Axis direction of fromPos -> toPos
function Position:getDirectionTo(toPosition)
local dir = DIRECTION_NORTH
if(self.x > toPosition.x) then
dir = DIRECTION_WEST
if(self.y > toPosition.y) then
dir = DIRECTION_NORTHWEST
elseif(self.y < toPosition.y) then
dir = DIRECTION_SOUTHWEST
end
elseif(self.x < toPosition.x) then
dir = DIRECTION_EAST
if(self.y > toPosition.y) then
dir = DIRECTION_NORTHEAST
elseif(self.y < toPosition.y) then
dir = DIRECTION_SOUTHEAST
end
else
if(self.y > toPosition.y) then
dir = DIRECTION_NORTH
elseif(self.y < toPosition.y) then
dir = DIRECTION_SOUTH
end
end
return dir
end
-- Animation frame magic effect
function animation(pos, playerpos, animationType)
if not Tile(Position(pos)):hasProperty(CONST_PROP_BLOCKPROJECTILE) then
if Position(pos):isSightClear(playerpos) then
if animationType == 0 then
Position(pos):sendMagicEffect(CONST_ME_POFF)
end
Position(pos):sendMagicEffect(CONST_ME_GROUNDSHAKER)
end
end
end
-- Stun animation magic effect
function stunAnimation(stunnedcreature, stunnedpos, counter)
if counter ~= 0 and Creature(stunnedcreature) then
stunnedpos:sendMagicEffect(CONST_ME_STUN)
counter = counter - 1
addEvent(stunAnimation, 500, stunnedcreature, stunnedpos, counter)
end
return true
end
-- Damage Formula
function onGetFormulaValues(player, skill, attack, factor)
local skillTotal = skill * attack
local levelTotal = player:getLevel() / 5
return -(((skillTotal * 0.06) + 13) + (levelTotal)), -(((skillTotal * 0.11) + 27) + (levelTotal))
end
local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat:setParameter(COMBAT_PARAM_BLOCKARMOR, 1)
combat:setArea(createCombatArea(hitArea))
combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")
function onCastSpell(creature, var)
-- Defaults
local centre = {}
local damageArea = {}
local pushTargets = {}
local blockedPos = {}
local playerPos = creature:getPosition()
local delay = 100
local stunDuration = 2000
-- Get creatures in squares around caster
local getTargets = Game.getSpectators(playerPos, false, false, 1, 1, 1, 1)
-- Shuffle targets so its random who prioritizes which squares/positions
shuffle(getTargets)
for _,target in pairs(getTargets) do
if target.uid ~= creature.uid then -- If target is not the caster
if not target:isNpc() then -- only target Players and Monsters
local targetPos = target:getPosition()
local playerDir = playerPos:getDirectionTo(targetPos)
if playerDir then
local nextPos = Position(targetPos):getBehindPos(playerDir, 1) -- Tile to push to
if Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID) or Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE) or Tile(nextPos):getCreatureCount() > 0 then -- If tile to push to is invalid/blocked
-- Alternative push positions
local secondaryPositions = {}
-- Get alternative push positions
if playerDir == DIRECTION_NORTH then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHEAST, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHWEST, 1))
elseif playerDir == DIRECTION_NORTHEAST then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTH, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_EAST, 1))
elseif playerDir == DIRECTION_EAST then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHEAST, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHEAST, 1))
elseif playerDir == DIRECTION_SOUTHEAST then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_EAST, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTH, 1))
elseif playerDir == DIRECTION_SOUTH then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHEAST, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHWEST, 1))
elseif playerDir == DIRECTION_SOUTHWEST then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTH, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_WEST, 1))
elseif playerDir == DIRECTION_WEST then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHWEST, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHWEST, 1))
elseif playerDir == DIRECTION_NORTHWEST then
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_WEST, 1))
table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTH, 1))
end
-- Shuffle alternative push positions
shuffle(secondaryPositions)
-- Check for valid positions
local validSecondary = false
for i = 1, #secondaryPositions do
if not validSecondary then
local position = secondaryPositions[i]
local creatureCheck = Tile(nextPos):getCreatureCount()
if not Tile(position):hasFlag(TILESTATE_FLOORCHANGE) then
if not Tile(position):hasProperty(CONST_PROP_BLOCKSOLID) and Tile(position):getCreatureCount() < 1 then -- Ensure alternative push position is valid
nextPos = secondaryPositions[i]
validSecondary = true
end
end
end
end
-- If valid alternative push position
if validSecondary and not isInArray(blockedPos, nextPos) then
table.insert(blockedPos, nextPos)
table.insert(pushTargets, {target.uid, nextPos})
else -- Monster is stuck, stun them against wall
if target:isPlayer() then
stunDuration = stunDuration / 2
end
-- Headbutt the wall fam
target:setDirection(playerDir)
nextPos:sendMagicEffect(CONST_ME_DRAWBLOOD)
-- Stun
local stun = Condition(CONDITION_STUN)
stun:setParameter(CONDITION_PARAM_TICKS, stunDuration)
target:addCondition(stun)
-- Mute
local mute = Condition(CONDITION_MUTED)
mute:setParameter(CONDITION_PARAM_TICKS, stunDuration)
target:addCondition(mute)
addEvent(stunAnimation, 0, target.uid, target:getPosition(), (stunDuration / 1000) * 2)
end
else -- Regular push position is valid
if not isInArray(blockedPos, nextPos) then
table.insert(blockedPos, nextPos)
table.insert(pushTargets, {target.uid, nextPos})
end
end
end
end
end
end
-- Push targets
for i = 1, #pushTargets do
local target = Creature(pushTargets[i][1])
target:teleportTo(pushTargets[i][2], true)
end
-- animation
local animationType = 0
for j = 1, #animationArea do
if j > 2 then
animationType = 1
end
for k,v in ipairs(animationArea[j]) do
for i = 1, #v do
if v[i] == 3 or v[i] == 2 then
centre.Row = k
centre.Column = i
elseif v[i] == 1 then
local darea = {}
darea.Row = k
darea.Column = i
darea.Delay = math.random(j * delay, (j * delay) + delay)
darea.Animation = animationType
table.insert(damageArea, darea)
end
end
end
end
for i = 1,#damageArea do
local modifierx = damageArea[i].Column - centre.Column
local modifiery = damageArea[i].Row - centre.Row
local animationPos = Position(playerPos)
animationPos.x = animationPos.x + modifierx
animationPos.y = animationPos.y + modifiery
local animationDelay = damageArea[i].Delay or 0
addEvent(animation, animationDelay, animationPos, playerPos, damageArea[i].Animation)
end
-- Execute Damage
return combat:execute(creature, var)
end
Edit: Fixed this line
target:setDirection(playerDir)
TBH this line should get the direction of the wall they're hitting, instead of assuming playerDir is right, improvement suggestion if you are using this spell
Last edited: