Ask a simple question, get a simple answer
Re: Ask a simple question, get a simple answer
(sigh - why are some things THAT complicate... )
Sorry, minmay, doesn't work. Probably, I am doing something wrong.
Does your code mean a) I have to re-define my spell as a projectile b) I have to use your code on an CastSpellComponent? I tried it still in an ItemActionComponent (of course in an onAttack hook).
Sorry, minmay, doesn't work. Probably, I am doing something wrong.
Does your code mean a) I have to re-define my spell as a projectile b) I have to use your code on an CastSpellComponent? I tried it still in an ItemActionComponent (of course in an onAttack hook).
Re: Ask a simple question, get a simple answer
Hey THOM,
minmays projectile script is good, I have based mine on that script and have no dramas at all.
I can try and step you through it
First! - paste this into a script entity (dungeon or external) - name it "projectileScripts"
Next! - define your spell - which you already have done
(here is simple projectile spell thats was on hand - someone elses spell actually)
- just paste this into whatever script you import for your spells (or not)
And here is a Weapon that will fire the spell (secondary action)
Note** projectileScripts has been running smoothly for a year or two now... its very easy!
And I have built in functionality for volleys of projectile spells .... you just need to assign numbers to volleyCount, & delay, (eg, 5, 0.5 - 5 projectiles, delay of 0.5s)
You just call it like this:
Hope this helps!
Akroma
minmays projectile script is good, I have based mine on that script and have no dramas at all.
I can try and step you through it
First! - paste this into a script entity (dungeon or external) - name it "projectileScripts"
SpoilerShow
Code: Select all
projectileSpellCaster = ""
projectileVolleyCount = 0
----------------------------------------------------------------------------------------------------checkwall()
function checkwall()
local direction = party.facing
local x = party.x
local y = party.y
local elevation = party.elevation
local myx = x
local myy = y
if direction == 0 then
myy = y - 1
elseif direction == 1 then
myx = x + 1
elseif direction == 2 then
myy = y + 1
elseif direction == 3 then
myx = x - 1
end
if not party.map:checkLineOfFire(x,y,myx,myy,elevation) then
return true
else
return false
end
end
------------------------------------------------------------------------------------------------
function extraCost(champion, skillLevel, cost)
if champion:getEnergy() < cost then
return false
else
return true
end
end
--------------------------------------------------------------------------------------------------------
function projectileSpell(champion, x, y, direction, elevation, skillLevel, projectile, power, volleyCount, delay, sound, cost)
local c = 1
projectileVolleyCount = 0
-----------------------------1 sound
if sound ~= nil then
playSound(sound)
end
-----------------------------
if checkwall() == true then
spawn(projectile, party.level, x, y, direction, elevation)
else
local a = spawn(projectile,party.level, x, y, direction, elevation)
a.projectile:setIgnoreEntity(party)
--------------------------------------------------------------power
if power ~= "" then
a.projectile:setAttackPower(power)
end
-----------------------------------------------------------ordinal
if champion then
c = champion:getOrdinal()
end
a.projectile:setCastByChampion(c)
-----------------------------------------------------------data
if a.data then
print("data")
end
-----------------------------------------------------------positioning
local left = nil
for i = 1,4 do
if party.party:getChampion(i):getOrdinal() == ord then
left = i == 1 or i == 3
break
end
end
local wpos = party:getWorldPosition()
local dx = nil
local dz = nil
if party.facing == 0 then
dx = left and -0.1 or 0.1
dz = -1
elseif party.facing == 1 then
dz = left and 0.1 or -0.1
dx = -1
elseif party.facing == 2 then
dx = left and 0.1 or -0.1
dz = 1
else -- party.facing == 3
dz = left and -0.1 or 0.1
dx = 1
end
a:setWorldPosition(vec(wpos[1]+dx,wpos[2]+1.35,wpos[3]+dz))
-----------------------------------------------------------------if volley
if volleyCount > 1 and delay ~= nil then
-----------------------------------------extra cost()
if cost ~= nil then
local amount = champion:getEnergy() - cost
champion:setEnergy(amount)
end
------------------------------------------------------------------------------------------------------------------------ repeatCount()
delayedCall("projectileScripts", delay, "volleyProjectileSpell", champion, projectile, power, volleyCount, delay, sound)
projectileVolleyCount = projectileVolleyCount + 1
print(volleyCount, delay, projectileVolleyCount, power)
end
end
projectileSpellCaster = c
end
-------------------------------------------------------------------------------------------------------------------
function volleyProjectileSpell(champion, projectile, power, volleyCount, delay, sound)
local x = party.x
local y = party.y
local direction = party.facing
local elevation = party.elevation
local dx,dy = getForward(party.facing)
if projectileVolleyCount == volleyCount then
projectileVolleyCount = 0
return false
else
if sound ~= nil then
playSound(sound)
end
if checkwall() == true then
spawn(projectile, party.level, x, y, direction, elevation)
else
local a = spawn(projectile,party.level, x, y, direction, elevation)
a.projectile:setIgnoreEntity(party)
a.projectile:setAttackPower(power)
local c = champion:getOrdinal()
a.projectile:setCastByChampion(c)
local left = nil
for i = 1,4 do
if party.party:getChampion(i):getOrdinal() == ord then
left = i == 1 or i == 3
break
end
end
local wpos = party:getWorldPosition()
local dx = nil
local dz = nil
if party.facing == 0 then
dx = left and -0.1 or 0.1
dz = -1
elseif party.facing == 1 then
dz = left and 0.1 or -0.1
dx = -1
elseif party.facing == 2 then
dx = left and 0.1 or -0.1
dz = 1
else -- party.facing == 3
dz = left and -0.1 or 0.1
dx = 1
end
a:setWorldPosition(vec(wpos[1]+dx,wpos[2]+1.35,wpos[3]+dz))
a:setSubtileOffset(math.random() - 0.5, math.random()- 0.5)
projectileVolleyCount = projectileVolleyCount + 1
print(volleyCount, delay, projectileVolleyCount, power)
delayedCall("projectileScripts", delay, "volleyProjectileSpell", champion, projectile, power, volleyCount, delay, sound)
end
end
projectileSpellCaster = champion:getOrdinal()
end
(here is simple projectile spell thats was on hand - someone elses spell actually)
- just paste this into whatever script you import for your spells (or not)
SpoilerShow
Code: Select all
defineSpell{
name = "plasma_bolt",
uiName = "Plasma Bolt",
gesture = 0,
manaCost = 0,
icon = 72,
spellIcon = 13,
hidden = true,
description = "",
onCast = function(champion, x, y, direction, elevation, skillLevel)
projectileScripts.script.projectileSpell(champion, x, y, direction, elevation, skillLevel, "plasma_bolt", 25, 3, 0.5, "fireball_launch", 5)
end,
}
defineObject{
name = "plasma_bolt",
baseObject = "base_spell",
components = {
{
class = "Particle",
particleSystem = "plasma_bolt",
},
{
class = "Light",
color = vec(1, 1, 0.25),
brightness = 40,
range = 10,
castShadow = true,
},
{
class = "Script",
name = "data",
source = [[
data = {}
function get(self,name)
return self.data[name]
end
function set(self,name,value)
self.data[name] = value
end]],
},
{
class = "Projectile",
spawnOffsetY = 1.35,
velocity = 12,
radius = 0.1,
hitEffect = "plasma_blast",
onProjectileHit = function(self, what, entity)
print(self.go.name, what, entity.name)
end,
},
{
class = "Sound",
sound = "lightning_bolt",
pitch = 1.4,
},
{
class = "Sound",
name = "launchSound",
sound = "lightning_bolt_launch",
pitch = 2,
},
{
class = "Sound",
name = "launchSound2",
sound = "lightning_bolt_launch",
pitch = 1.5,
},
},
}
defineObject{
name = "plasma_blast",
baseObject = "base_spell",
components = {
{
class = "Particle",
particleSystem = "plasma_hit",
destroyObject = true,
rotation = vec(90,0,0),
},
{
class = "Light",
color = vec(1, 0.4, 0),
brightness = 96,
range = 16,
fadeOut = 3,
disableSelf = true,
},
{
class = "Sound",
sound = "magma_golem_meteor_fall",
soundType = "ambient",
pitch = 2,
},
{
class = "Sound",
sound = "gun_shot_cannon",
soundType = "ambient",
pitch = 1.5,
},
},
}
defineParticleSystem{
name = "plasma_bolt",
emitters = {
-- fog
{
emissionRate = 10,
emissionTime = 0,
maxParticles = 1000,
boxMin = {-0.05,-0.05,-0.05},
boxMax = { 0.05, 0.05, 0.05},
sprayAngle = {0,360},
velocity = {0.1,0.2},
objectSpace = true,
texture = "assets/textures/particles/fog.tga",
lifetime = {3,3},
color0 = {0.2, 0.2, 0},
opacity = 1,
fadeIn = 0.2,
fadeOut = 2.2,
size = {0.2, 0.4},
gravity = {0,0,0},
airResistance = 0.1,
rotationSpeed = 3,
blendMode = "Additive",
},
-- stars
{
emissionRate = 512,
emissionTime = 0,
maxParticles = 1024,
boxMin = {-0.1, -0.1, -0.1},
boxMax = { 0.1, 0.1, 0.1},
sprayAngle = {0,360},
velocity = {0.01,0.2},
objectSpace = false,
texture = "assets/textures/particles/dust_particle_dif.tga",
lifetime = {0.4,1},
color0 = {1.0,1.0,0},
opacity = 1,
fadeIn = 0.001,
fadeOut = 0.4,
size = {0.05, 0.1},
gravity = {0,0,0},
airResistance = -2,
rotationSpeed = 7,
blendMode = "Additive",
},
-- glow
{
spawnBurst = true,
emissionRate = 1,
emissionTime = 0,
maxParticles = 1,
boxMin = {0,0,0},
boxMax = {0,0,0},
sprayAngle = {0,30},
velocity = {0,0},
texture = "assets/textures/particles/glow.tga",
lifetime = {1000000, 1000000},
colorAnimation = false,
color0 = {1,1,0.25},
opacity = 1,
fadeIn = 0.1,
fadeOut = 0.1,
size = {1.0, 1.0},
gravity = {0,0,0},
airResistance = 1,
rotationSpeed = 2,
blendMode = "Additive",
objectSpace = true,
},
{
emissionRate = 128,
emissionTime = 0,
maxParticles = 128,
sprayAngle = {0,180},
velocity = {256, 256},
boxMin = {0,0,0},
boxMax = {0,0,0},
texture = "assets/textures/particles/lightning01.tga",
frameRate = 4,
frameSize = 256,
frameCount = 4,
lifetime = {0.2,0.4},
color0 = {6.5,2.5,0},
opacity = 1,
fadeIn = 0.001,
fadeOut = 0.3,
size = {0.3, 0.5},
gravity = {0,0,0},
airResistance = 1024,
rotationSpeed = 0,
blendMode = "Additive",
},
}
}
defineParticleSystem{
name = "plasma_hit",
emitters = {
-- sparks
{
spawnBurst = true,
maxParticles = 256,
boxMin = {-0.1, -0.1, -0.1},
boxMax = { 0.1, 0.1, 0.1},
sprayAngle = {0,360},
velocity = {8,12},
objectSpace = false,
texture = "assets/textures/particles/teleporter.tga",
lifetime = {0.2,1},
color0 = {1.0,2.0,4.0},
opacity = 1,
fadeIn = 0.001,
fadeOut = 1,
size = {0.05, 0.3},
gravity = {0,0,0},
airResistance = 8,
rotationSpeed = 2,
blendMode = "Additive",
},
-- fog
{
spawnBurst = true,
maxParticles = 50,
sprayAngle = {0,360},
velocity = {0,3},
objectSpace = true,
texture = "assets/textures/particles/fog.tga",
lifetime = {0.4,0.6},
color0 = {0.15, 0.35, 1},
opacity = 0.7,
fadeIn = 0.1,
fadeOut = 0.3,
size = {1, 2},
gravity = {0,0,0},
airResistance = 0.5,
rotationSpeed = 1,
blendMode = "Additive",
},
-- glow
{
spawnBurst = true,
emissionRate = 1,
emissionTime = 0,
maxParticles = 1,
boxMin = {0,0,-0.1},
boxMax = {0,0,-0.1},
sprayAngle = {0,30},
velocity = {0,0},
texture = "assets/textures/particles/glow.tga",
lifetime = {0.5, 0.5},
colorAnimation = false,
color0 = {0.5, 1, 2},
opacity = 1,
fadeIn = 0.01,
fadeOut = 0.5,
size = {1, 1},
gravity = {0,0,0},
airResistance = 1,
rotationSpeed = 2,
blendMode = "Additive",
},
{
emissionRate = 512,
emissionTime = 2,
maxParticles = 1024,
boxMin = {-0.75,0,-1.5},
boxMax = {0.75,0,1.3},
sprayAngle = {0,10},
velocity = {0.1, 32},
texture = "assets/textures/particles/rock_shard.tga",
frameRate = 0,
frameSize = 64,
frameCount = 1,
lifetime = {1, 6},
color0 = {2, 0.2, 0},
opacity = 1,
fadeIn = 0.001,
fadeOut = 1,
size = {0.03, 0.1},
gravity = {0,-20,0},
airResistance = 2,
rotationSpeed = 0,
blendMode = "Translucent",
--depthBias = -0.002,
clampToGroundPlane = true,
},
{ -- flame clouds
emissionRate = 2048,
emissionTime = 0.5,
maxParticles = 1024,
boxMin = {-0.75,0,-1.5},
boxMax = {0.75,0,1.3},
sprayAngle = {0,10},
velocity = {0.1, 4},
texture = "assets/textures/particles/torch_flame.tga",
frameRate = 35,
frameSize = 64,
frameCount = 16,
lifetime = {0.5, 1.25},
colorAnimation = true,
color0 = {2, 2, 2},
color1 = {1.0, 1.0, 1.0},
color2 = {1.0, 0.5, 0.25},
color3 = {1.0, 0.3, 0.1},
opacity = 1,
fadeIn = 0.001,
fadeOut = 1,
size = {0.2, 0.5},
gravity = {0,0.2,0},
airResistance = 0.2,
rotationSpeed = 1,
blendMode = "Additive",
--depthBias = -0.002,
},
{ -- floaty sparks
emissionRate = 1024,
emissionTime = 2,
maxParticles = 2048,
boxMin = {-0.75,0,-1.5},
boxMax = {0.75,0,1.3},
sprayAngle = {0,10},
velocity = {8, 24},
texture = "assets/textures/particles/fire_elemental_spark.tga",
lifetime = {1, 2.8},
colorAnimation = true,
color0 = {1, 1, 0.1},
color1 = {1, 0.5, 0.1},
color2 = {1, 0.3, 0.1},
color3 = {1.0, 0.2, 0.1},
opacity = 1,
fadeIn = 0.001,
fadeOut = 2,
size = {0.1, 0.3},
gravity = {0,0,0},
rotationSpeed = 5,
airResistance = 1,
blendMode = "Additive",
--depthBias = -0.002,
},
}
}
SpoilerShow
Code: Select all
defineObject{
name = "longbow2",
baseObject = "base_item",
components = {
{
class = "Model",
model = "assets/models/items/longbow.fbx",
},
{
class = "Item",
uiName = "Crookhorn Longbow",
description = "A powerful bow made from the horns of a crookhorn ram.",
gfxIndex = 165,
gfxIndexPowerAttack = 98,
impactSound = "impact_blunt",
primaryAction = "shockArrow",
secondaryAction = "plasmaBolt",
weight = 1.6,
traits = { "missile_weapon" },
},
{
class = "RangedAttack",
name = "shockArrow",
attackPower = 16,
cooldown = 4.5,
attackSound = "swipe_bow",
ammo = "arrow",
repeatCount = 5,
repeatDelay = 0.2,
spread = 0.3,
projectileItem = "shock_arrow",
},
{
class = "CastSpell",
name = "plasmaBolt",
uiName = "Plasma Bolt",
buildup = 2.0,
cooldown = 3.5,
charges = 20,
spell = "plasma_bolt",
requirements = { "concentration", 2 , "missile_weapons", 2, },
energyCost = 10,
gameEffect = "Shoot an arrow enchanted with the energy of storms.",
},
},
tags = { "weapon", "weapon_missile" },
}
And I have built in functionality for volleys of projectile spells .... you just need to assign numbers to volleyCount, & delay, (eg, 5, 0.5 - 5 projectiles, delay of 0.5s)
Code: Select all
projectileSpell(champion, x, y, direction, elevation, skillLevel, projectile, power, volleyCount, delay, sound, cost)
You just call it like this:
Code: Select all
projectileScripts.script.projectileSpell(champion, x, y, direction, elevation, skillLevel, "plasma_bolt", 25, 3, 0.5, "fireball_launch", 5)
Hope this helps!
Akroma
Labyrinth of Lies (viewtopic.php?f=14&t=4400)
Legacy of Lies (viewtopic.php?f=22&t=12983&hilit=+legacy)
Legacy of Lies (viewtopic.php?f=22&t=12983&hilit=+legacy)
Re: Ask a simple question, get a simple answer
It is just a demonstration of how to spawn a projectile in the same place it would be created by the builtin Fireball/Frostbolt/Lightning Bolt/Poison Bolt spells. You would use it wherever you want to launch a projectile. A plain ItemComponent's onAttack hook will work, so will anywhere else, you just need to supply the champion, x, y, direction, and elevation. You don't need to define a new spell or use a ScriptComponent unless you want to.THOM wrote:(sigh - why are some things THAT complicate... )
Sorry, minmay, doesn't work. Probably, I am doing something wrong.
Does your code mean a) I have to re-define my spell as a projectile b) I have to use your code on an CastSpellComponent? I tried it still in an ItemActionComponent (of course in an onAttack hook).
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Re: Ask a simple question, get a simple answer
if I do it this way - it doesn't work:
Code: Select all
{
class = "ItemAction",
name = "waterbolt",
uiName = "Water Bolt",
cooldown = 5,
onAttack = function(champion, x, y, direction, elevation)
local spl = spawn ("water_bolt",party.level,party.x,party.y,party.facing,party.elevation)
spl.projectile:setIgnoreEntity(party)
-- Set cast by champion so that experience is awarded for kills.
local ord = champion:getOrdinal()
spl.projectile:setCastByChampion(ord)
-- Simulate the position of a player-cast spell.
local left = nil
for i = 1,4 do
if party.party:getChampion(i):getOrdinal() == ord then
left = i == 1 or i == 3
break
end
end
local wpos = party:getWorldPosition()
local dx = nil
local dz = nil
if party.facing == 0 then
dx = left and -0.1 or 0.1
dz = -1
elseif party.facing == 1 then
dz = left and 0.1 or -0.1
dx = -1
elseif party.facing == 2 then
dx = left and 0.1 or -0.1
dz = 1
else -- party.facing == 3
dz = left and -0.1 or 0.1
dx = 1
end
spl:setWorldPosition(vec(wpos[1]+dx,wpos[2]+1.35,wpos[3]+dz))
end,
},
Re: Ask a simple question, get a simple answer
Code: Select all
ItemActionComponent.onAttack(self, champion, slot, chainIndex)
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Re: Ask a simple question, get a simple answer
so that means???
Re: Ask a simple question, get a simple answer
I really didn't think I would have to explain this part...
It means your function declaration is wrong. Change it to
and then the arguments will match up with what you wanted.
It means your function declaration is wrong. Change it to
Code: Select all
onAttack = function(self, champion, slot, chainIndex)
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Re: Ask a simple question, get a simple answer
sorry for bothering you, but for me is (self, champion, slot, chainIndex) and (champion, x, y, direction, elevation) something complete different that you cannot exchange just because.
BTW: still don't work
BTW: still don't work
Code: Select all
defineObject{
name = "water_shooter",
baseObject = "base_item",
components = {
{
class = "Model",
model = "assets/models/items/revolver.fbx",
material = "zarchton_wand",
},
{
class = "Item",
uiName = "Water Shooter",
description = "A strange mechanics makes this weapon compressing water and shooting it out in some kind of a jet.",
gfxAtlas = "mod_assets/textures/iconatlas/iconatlas.dds",
gfxIndex = 33,
weight = 1.5,
traits = { "weapon" },
onAttack = function(self, champion, slot, chainIndex)
local spl = spawn ("water_bolt",party.level,party.x,party.y,party.facing,party.elevation)
spl.projectile:setIgnoreEntity(party)
-- Set cast by champion so that experience is awarded for kills.
local ord = champion:getOrdinal()
spl.projectile:setCastByChampion(ord)
-- Simulate the position of a player-cast spell.
local left = nil
for i = 1,4 do
if party.party:getChampion(i):getOrdinal() == ord then
left = i == 1 or i == 3
break
end
end
local wpos = party:getWorldPosition()
local dx = nil
local dz = nil
if party.facing == 0 then
dx = left and -0.1 or 0.1
dz = -1
elseif party.facing == 1 then
dz = left and 0.1 or -0.1
dx = -1
elseif party.facing == 2 then
dx = left and 0.1 or -0.1
dz = 1
else -- party.facing == 3
dz = left and -0.1 or 0.1
dx = 1
end
spl:setWorldPosition(vec(wpos[1]+dx,wpos[2]+1.35,wpos[3]+dz))
end,
},
{
class = "ItemAction",
name = "waterbolt",
uiName = "Water Bolt",
cooldown = 5,
},
},
}
Re: Ask a simple question, get a simple answer
You are the one who exchanged function declarations "just because". You took the declaration for an onCastSpell hook function, and pasted it as the declaration for an ItemActionComponent.onAttack hook function. These hooks receive different arguments, so using the same declaration is unlikely to make semantic sense, and in fact the two hooks don't even receive the same number of arguments.
Anyway, now the problem is that you just moved the onAttack field from the ItemActionComponent to the ItemComponent. Move it back to the ItemActionComponent.
Anyway, now the problem is that you just moved the onAttack field from the ItemActionComponent to the ItemComponent. Move it back to the ItemActionComponent.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Re: Ask a simple question, get a simple answer
I give up.
...the function won't be executed. I inserted a hudPrint just for to check. Nope, no reaction.
(and: yes, I moved back the function into the ItemActionComponent.)
...the function won't be executed. I inserted a hudPrint just for to check. Nope, no reaction.
(and: yes, I moved back the function into the ItemActionComponent.)