that you can use "mouse gestures" or native method, both will work in parallel. The goal of this script was to reduce the time spent for staring of the right bottom corner of the screen, and I think that I succeeded.
I wanted to keep this simple as possible, so actually there isn't many gestures used, only action where gestures is used is selecting the active champion,
so don't look any fancy gesture detection algorithms from this script
INSTALLATION
Just copy paste this script to some script entity, for example named mouse_gesture_fighting.
And you must have party.onDrawGui-hook defined, it can be empty or not, it's just needed for the onDrawGui-connector which doesn't get called if onDrawGui-hook is not defined.
Code: Select all
--You can modify these properties
--Show instructions on Gui
showInstructions = true
-- if false you must call enable() to enable mouse gesture fighting
-- and you can call disable() to disable it
enabledByDefault = true
--Don't modify below this unless you know what you are doing
--This script is pretty messy, sorry about that. But it works so I don't mind :)
rmDown=false --RMB down
lmDown = false --LMB down
rmStartPos = {} --RMB press position
rmStartTime = 0 --RMB press start time
activeChampion = false --Number of the active champion (0-4)
powerAttack = false --Power attack buildup started
powerAttackReady = false --Power attack fully charged
powerAttackBuildupTime = false --Buildup time
powerAttackThreshold = 0.7 --How long RMB must be pressed before the power attack starts charging
powerAttackAlpha = 0
alphaModifier = 10
cancelled = false --Action cancelled
secondHandActivated = false
runeWidth = 50
castingSpell = false
castStartX = 0
castStartY = 0
selectedRunes = ''
prevRune = 0
prevRune2 = 0
function enable()
party.party:addConnector('onDrawGui',self.go.id,'main')
end
function disable()
party.party:removeConnector('onDrawGui',self.go.id,'main')
end
if enabledByDefault then
enable()
end
function main(party,g)
if showInstructions then
instructions(g)
end
if cancelled then
--cancelled and mouse released
if not g.mouseDown(0) then
reset()
end
return
end
if castingSpell then
checkCancel(g,400)
castSpell(g)
return
end
if g.mouseDown(0) then
onLeftMouseDown(party,g)
else
if rmDown then
if activeChampion then -- mouse button released
local champ = party:getChampion(activeChampion)
championAttack(g,champ)
else
reset()
end
end
end
end
function onLeftMouseDown(party,g)
checkCancel(g,400)
if not rmDown then -- mouse button pressed
rmStartPos = {g.mouseX,g.mouseY}
rmStartTime = Time.currentTime()
rmDown=true
GameMode.setGameFlag('DisableMouseLook',true)
else -- mouse button hold
checkChangeHand(g)
if not activeChampion then
activeChampion = getChampionNumber(g)
end
if activeChampion then
onChampionActive(g)
end
end
end
function onChampionActive(g)
local champ = party.party:getChampion(activeChampion)
local readyHand = championGetReadyHand(champ)
if readyHand then
local item = champ:getItem(readyHand)
if not powerAttack and item and Time.currentTime() - rmStartTime > powerAttackThreshold and championCanDoPowerAttack(champ,readyHand) then
powerAttackBuildupTime = itemGetPowerAttack(item):getBuildup()
playSound('power_attack_charging')
powerAttack = true
end
if item then
if powerAttack then
drawPowerAttack(g,item)
end
g.color(255,255,255,255)
drawItem(g,item,g.mouseX,g.mouseY)
else
if champ:hasTrait('hand_caster') then
g.drawGuiItem('UnarmedAttackMageLeft',g.mouseX,g.mouseY)
else
g.drawGuiItem('UnarmedAttackLeft',g.mouseX,g.mouseY)
end
end
end
end
function checkCancel(g,distanceFromRightEdge)
if g.mouseX > g.width - distanceFromRightEdge or getMouseItem() then
cancelled = true
end
end
function reset()
rmDown=false
rmStartPos = {}
powerAttackAlpha = 0
powerAttackReady = false
alphaModifier = 10
powerAttack = false
rmStartTime = 0
activeChampion = false
powerAttackBuildupTime = 0
castingSpell = false
cancelled = false
secondHandActivated = false
lmDown = false
GameMode.setGameFlag('DisableMouseLook',false)
end
function drawPowerAttack(g,item)
if not powerAttackReady and rmStartTime + powerAttackThreshold + powerAttackBuildupTime < Time.currentTime() then
--print(rmStartTime,powerAttackBuildupTime,Time.currentTime())
powerAttackReady = true
playSound('power_attack_ready')
end
powerAttackAlpha = powerAttackAlpha + alphaModifier
if powerAttackAlpha >= 255 then
powerAttackAlpha = 255
alphaModifier = -1
end
if alphaModifier < 0 and powerAttackAlpha < 150 then
alphaModifier = 1
end
g.color(255,255,255,powerAttackAlpha)
drawItem(g,item,g.mouseX,g.mouseY,powerAttack)
end
function itemGetPowerAttack(item)
local pattack = item:getSecondaryAction()
if pattack then
return item.go:getComponent(pattack)
end
end
function championCanDoPowerAttack(champ,hand)
local item = champ:getItem(hand)
if not item then return false end
local powerAttack = itemGetPowerAttack(item)
if not powerAttack then return false end
if champ:getEnergy() < powerAttack:getEnergyCost() then
return false
end
local requirements = powerAttack:getRequirements()
if not requirements then return true end
for i=1,#requirements,2 do
if champ:getSkillLevel(requirements[i]) < requirements[i+1] then
return false
end
end
--print( powerAttack:getUiName())
return true
end
function drawItem(g,item,x,y,pAttack)
local index = item:getGfxIndex()
if pAttack then
index = item:getGfxIndexPowerAttack()
end
local atlasNumber = math.floor(index/200)
if index >= 200 then
index = index - 200 * (atlasNumber)
end
local atlasIndex = index%169
local row = math.floor(atlasIndex/13)
local col = atlasIndex%13
local atlas = 'assets/textures/gui/items.tga'
if atlasNumber > 0 then
atlas = 'assets/textures/gui/items_'..(atlasNumber+1)..'.tga'
end
g.drawImage2(atlas, x, y, col*75, row*75, 75,75, 75, 75)
end
function checkChangeHand(g)
if g.mouseDown(2) then
if not lmDown then
lmDown = true
secondHandActivated = not secondHandActivated
powerAttack = false
powerAttackReady = false
powerAttackBuildupTime = false
powerAttackAlpha = 0
alphaModifier = 10
rmStartTime = Time.currentTime()
end
else
lmDown = false
end
end
function championPowerAttack(champ,hand)
local item = champ:getItem(hand)
if not item then return false end
local powerAttack = itemGetPowerAttack(item)
champ:attack(hand,true)
champ:setEnergy(champ:getEnergy() - powerAttack:getEnergyCost())
end
function championGetReadyHand(champ)
if secondHandActivated then
local item = champ:getItem(2)
if item then
if (itemIsWeapon(item) or itemIsWand(item)) and champ:isReadyToAttack(2) then
return 2
end
elseif champ:isReadyToAttack(2) then
return 2
end
end
if champ:isReadyToAttack(1) then
local item = champ:getItem(1)
if item then
if itemIsWeapon(item) or itemIsWand(item) then
return 1
end
elseif champ:hasTrait('hand_caster') then
return 1
end
end
if champ:isReadyToAttack(2) then
local item = champ:getItem(2)
if item and (itemIsWeapon(item) or itemIsWand(item)) then --dual wielding
return 2
end
if not item then
return 2
end
end
end
function itemIsWand(item)
return item.go:getComponent('runepanel') ~= nil
end
function itemIsWeapon(item)
if not item then return false end
return item.go.meleeattack or item.go.rangedattack or item.go.throwattack or item.go.firearmattack
end
function championAttack(g,champ)
local hand = championGetReadyHand(champ)
if not hand then
reset()
return
end
if powerAttackReady and championCanDoPowerAttack(champ,hand) then
championPowerAttack(champ,hand)
reset()
else
local item = champ:getItem(hand)
if item then
if itemIsWeapon(item) then
champ:attack(hand,false)
reset()
elseif itemIsWand(item) then
castSpell(g)
end
else
if champ:hasTrait('hand_caster') and champ:isReadyToAttack(1) then
castSpell(g)
else
champ:attack(hand,false)
reset()
end
end
end
end
function getDirection(g)
local distX = rmStartPos[1] - g.mouseX
local distY = rmStartPos[2] - g.mouseY
if math.abs(distX) < 50 and math.abs(distY) < 50 then
return nil
end
local dirX = iff(distX < 0,1,-1)
local dirY = iff(distY < 0,1,-1)
return dirX,dirY
end
function getChampionNumber(g)
local dirX,dirY = getDirection(g)
if dirX == nil then return false end
if dirX == -1 and dirY == -1 then return 1 end
if dirX == 1 and dirY == -1 then return 2 end
if dirX == -1 and dirY == 1 then return 3 end
return 4
end
function castSpell(g)
if not castingSpell then
castingSpell = true
selectingRunes = false
castStartX,castStartY = g.mouseX,g.mouseY
else
if not selectingRunes and g.mouseDown(0) then
selectingRunes = true
end
if selectingRunes and not g.mouseDown(0) then
castingSpell = false
selectingRunes = false
--hudPrint('selected runes '..selectedRunes)
local champ = party.party:getChampion(activeChampion)
if selectedRunes ~= '' then
champ:castSpell(tonumber(selectedRunes))
end
selectedRunes = ''
prevRune = 0
reset()
end
drawRunes(g)
end
end
function drawRune(g,number,x,y,w,h)
g.drawGuiItem2('SpellRunes', x, y, number*68-68, 0, 68, 60, w, h)
end
function drawRunes(g)
for i=1,9 do
local x,y = (i-1)%3*runeWidth,math.floor((i-1)/3)*runeWidth
if string.find(selectedRunes,tostring(i)) then
g.color(255, 255, 255, 255)
else
g.color(150, 150, 150, 255)
end
drawRune(g,i,castStartX+x,castStartY+y,runeWidth,runeWidth)
if g.mouseDown(0) and prevRune ~= i and prevRune2 ~= i and guiMouseInRect(g,castStartX+x,castStartY+y,runeWidth,runeWidth) then
selectedRunes = selectedRunes..i
prevRune2 = prevRune
prevRune = i
end
end
end
function guiMouseInRect(g, bx, by, bw, bh)
return (g.mouseX >= bx) and (g.mouseX <= bx + bw)
and (g.mouseY >= by) and (g.mouseY <= by + bh)
end
function instructions(g)
local w,h,x,y,gap = 300,0,200,30,20
w,h = g.drawParagraph("ATTACKING\n\nHold the right mouse button, drag it towards some corner of the screen and release. \nLeft up = champion 1, \nRight up = champion 2 etc...",x,y,w)
y = y + h + gap
w,h = g.drawParagraph("POWER ATTACK\n\nHold the mouse until the power attack is charged and then release the button.",x,y,w)
y = y + h + gap
w,h = g.drawParagraph("CHANGING WEAPONS\n\nRight click while holding left mouse button.",x,y,w)
y = y + h + gap
w,h = g.drawParagraph("CASTING A SPELL\n\nTry Attacking with wizard, you will figure it out.",x,y,w)
y = y + h + gap
w,h = g.drawParagraph("DUAL WIELD ATTACK\n\nYou can attack 2 times in a row quickly while dual wielding(no need to change the weapon).",x,y,w)
y = y + h + gap
w,h = g.drawParagraph("CANCEL ACTION\n\nMove mouse to the right edge of the screen while holding the LMB.",x,y,w)
y = y + h + gap
g.drawGuiItem('ButtonClose',x,y)
if g.button('close',x,y,100,30) then
showInstructions = false
end
g.color(255,255,255,20)
g.drawRect(g.width-400,0,400,g.height)
g.color(255,255,255,255)
w,h = g.drawParagraph("CANCEL ATTACK AREA",g.width-350,300,400)
end
The original opening post:
SpoilerShow
I have seen people complaining that they would like to be able to watch the monsters while in battle instead of the bottom right corner of the screen. It don't see it as a big issue, but it would be nice to be able to watch those beautiful graphics more. So I just started to develop an alternative attack system with mouse gestures and I was able to put together something promising (In my opinion). But I would like to get some feedback from other people before I sink more time in to it, so do you guys think that this is something that is worth developing further or is it just a bad idea? Would you like to use something like this in your mods?
Here is a really simple dungeon for testing purposes:
https://drive.google.com/file/d/0B7cR7s ... sp=sharing
ATTENTION: this is very experimental and unpolished feature, so expect some problems, but I hope you get the idea.
How it works:
Attacking with weapons
(only left hand weapons supported atm., and no dual wielding )
Just hold left mouse button down, drag and release.
Left up: Champion 1
Right up: Champion 2
Left down: Champion 3
Right down: Champion 4
Special attack
(This is really simple and unfinished feature, and I'm not even sure if it can be implemented properly)
hold mouse button over 0.5 seconds
Casting spells
Just like attacking with weapons, but when you release the button the runes are drawn at the location of the mouse cursor and you can select runes by holding the mouse button down again.
Current runes are ugly, and if I'm going to continue developing this further I will definitely replace them with better looking images.
Here is a really simple dungeon for testing purposes:
https://drive.google.com/file/d/0B7cR7s ... sp=sharing
ATTENTION: this is very experimental and unpolished feature, so expect some problems, but I hope you get the idea.
How it works:
Attacking with weapons
(only left hand weapons supported atm., and no dual wielding )
Just hold left mouse button down, drag and release.
Left up: Champion 1
Right up: Champion 2
Left down: Champion 3
Right down: Champion 4
Special attack
(This is really simple and unfinished feature, and I'm not even sure if it can be implemented properly)
hold mouse button over 0.5 seconds
Casting spells
Just like attacking with weapons, but when you release the button the runes are drawn at the location of the mouse cursor and you can select runes by holding the mouse button down again.
Current runes are ugly, and if I'm going to continue developing this further I will definitely replace them with better looking images.