<aside> ⏰
The PLAYER script is here in three parts and finally the effect is placed via event to actor script
you can copy paste these in order to single script except the actor one.
</aside>
<aside> ⚙
the actor script is simply overpowered diminishing fatigue for test
local types = require('openmw.types')
local self = require('openmw.self')
local function modification()
types.Actor.stats.dynamic.fatigue(self).current = types.Actor.stats.dynamic.fatigue(self).current - 100
end
return { eventHandlers = { modification = modification } }
</aside>
local core = require('openmw.core')
local I = require('openmw.interfaces')
local self = require('openmw.self')
local nearby = require('openmw.nearby')
local util = require('openmw.util')
local camera = require('openmw.camera')
local time = require('openmw_aux.time')
local types = require('openmw.types')
local ui = require('openmw.ui')
local count = 0 -- counting init
local R = 250 -- the circle radius
local end_seconds = 10
local used_spell = "fire bite"
I.AnimationController.addTextKeyHandler('spellcast', function(groupname, key)
if key.sub(key, #key - 6) == 'release' then
-- spell to use
if types.Actor.getSelectedSpell(self).id == used_spell then
-- vector to screen's center
local centervect = camera.viewportToWorldVector(util.vector2(0.5,0.5)):normalize()
local cam_pos = camera.getPosition()
-- getting the terrain or water collision
hitpos = nearby.castRay(cam_pos , cam_pos + centervect * 2000,
{ ignore = self,
collisionType = nearby.COLLISION_TYPE.HeightMap + nearby.COLLISION_TYPE.Water }
).hitPos
--print(hitpos) -- debug
-- not in interiors for landheight usage
if self.cell.isExterior == false then
ui.showMessage("not inside")
end
--condition to start the spell, exteriors only
if count == 0 and hitpos and self.cell.isExterior then
timer()
end
end
end
end)
function effects() -- effects to do
local acts = nearby.actors
for a, _ in pairs(acts) do
-- for actors inside the circle
if (hitpos - acts[a].position):length() < R then
-- the effect
acts[a]:sendEvent("modification")
print(acts[a].recordId)
end
end
end
function timer() -- timer function to spawn vfx
-- spell effect and it's model to use fo spawn
local effect = core.magic.effects.records[core.magic.EFFECT_TYPE.FireDamage].hitStatic
local model = types.Static.records[effect].model
-- timer itself
stop = time.runRepeatedly(function()
print("time", count)
-- counting to stop timer at certain amount
count = count + 1
-- for eight spawns, 45 * 8 = 360 circle
for i= 1 , 8 do
-- x and y by degrees to radians
local x = R * math.cos(math.rad(45)*i)
local y = R * math.sin(math.rad(45)*i)
-- start of the using x,y for positions
local trans = util.transform
local rotate = trans.rotateZ(self.rotation:getYaw()) * util.vector3(x, y ,0)
-- the logic for z height in exterior, interior might need castray.
local z
local land = core.land.getHeightAt(hitpos + rotate, self.cell)
if land < self.cell.waterLevel then
z = self.cell.waterLevel
else
z = land
end
-- final spawn positions and the vfx
local pos = util.vector3(hitpos.x,hitpos.y,z) + rotate
core.sendGlobalEvent('SpawnVfx', {model = model, position = pos })
end
-- the effect(s) is in separate function
-- also the determining inside of the circle position
-- you can do also other resultng effects here
effects()
-- stops the timer after 10 seconds and allows new casting
if count > end_seconds then
stop()
count = 0
end
-- seconds per spawn
end, 1 * time.second)
end