Having some trouble with shootProjectile

Ask for help about creating mods and scripts for Grimrock 2 or share your tips, scripts, tools and assets with other modders here. Warning: forum contains spoilers!
User avatar
Prozail
Posts: 158
Joined: Mon Oct 27, 2014 3:36 pm

Re: Having some trouble with shootProjectile

Post by Prozail »

AndakRainor wrote:Do you know how to delay and move the start positions of multiple projectiles to recreate the meteor spell ?
My code has a SetWorldPosition, if you spawn several, just set different positions. Delaying them is a bit tricker but im sure it can be done either through chaining spells, or with delayCall somehow.

Also for the problem with throwing rocks and arrows, this has not yet been solved.. I'm still at the "Item is not flying" error...(I've gone through pretty much all of the ingame lua, and it's just not done in LoG2.)

I've had an idea to create an arrow-shooting dummy-monster, kindof like the spore_mushroom.
spikedsynapse
Posts: 4
Joined: Sun Dec 07, 2014 4:53 am

Re: Having some trouble with shootProjectile

Post by spikedsynapse »

Has anyone figured this out yet?

To me this is kind of a staple of classic dungeon crawls.
MrChoke
Posts: 324
Joined: Sat Oct 25, 2014 7:20 pm

Re: Having some trouble with shootProjectile

Post by MrChoke »

spikedsynapse wrote:Has anyone figured this out yet?

To me this is kind of a staple of classic dungeon crawls.
Prozail's reply in this thread does work. I think it is the way to do it with Grimrock 2. My guess is shootProjectile() needs to get removed from the scripting reference.
User avatar
Prozail
Posts: 158
Joined: Mon Oct 27, 2014 3:36 pm

Re: Having some trouble with shootProjectile

Post by Prozail »

I tried a different approach to the fire-an-arrow problem, and tried to make it into a spell...

It sortof works.. but there are a few issues as to what it actually hits...

Code: Select all


defineObject{
	name = "projectile_arrow_hit",
	baseObject = "base_spell",
	components = {
		{
			class = "Particle",
			particleSystem = "hit_dust",
			destroyObject = true,
		},
	},
}

defineObject{
   name ="projectile_arrow",
   baseObject = "base_spell",
   components = {
		{
			class = "Model",
			model = "assets/models/items/arrow.fbx",
			rotation = vec(0,90,0)
		},
		{
			class = "Projectile",
			spawnOffsetY = 1.15,
			velocity = 15.0,
			radius = 0.1,
			hitEffect = "projectile_arrow_hit",
			onProjectileHit = function(self, what, entity)
				print("onHit",self,what,entity)
				self.go:spawn("arrow")
				if entity and entity.name == "party" then
					local r = math.random(1,4)
					entity.party:getChampionByOrdinal(r):damage(rollDamage(10),"physical")
				end
			end
		}
	},
}
User avatar
Aisuu
Posts: 61
Joined: Fri Oct 31, 2014 2:07 pm

Re: Having some trouble with shootProjectile

Post by Aisuu »

I got it working like this. Only issue is with impact sound. Its same, whether it hit party or wall.
SpoilerShow

Code: Select all

defineObject{
   name ="projectile_arrow",
   baseObject = "base_spell",
   components = {
      {
         class = "Model",
         model = "assets/models/items/arrow.fbx",
         rotation = vec(0,90,0)
      },
      {
         class = "Projectile",
         spawnOffsetY = 1.15,
         velocity = 15.0,
         radius = 0.1,
         hitEffect = "projectile_arrow_hit",
      },
		{
			class = "Sound",
			name = "launchSound",
			sound = "swipe_bow",
		}
   },
}

defineObject{
   name = "projectile_arrow_hit",
   baseObject = "base_spell",
   components = {
	  {
			class = "TileDamager",
			attackPower = 10,
			damageType = "physical",
			screenEffect = "damage_screen",
			sound = "projectile_hit_party",
		}
   },
}
User avatar
QuintinStone
Posts: 72
Joined: Sat Nov 01, 2014 9:58 pm

Re: Having some trouble with shootProjectile

Post by QuintinStone »

Haha! I went the same route and made it a spell! :lol:

Code: Select all

defineObject{
	name = "dart_spell",
	baseObject = "base_spell",
	components = {
		{
			class = "Model",
			model = "assets/models/items/blowpipe_dart.fbx",
			rotation = vec(0, 90, 0),
		},
		{
			class = "Projectile",
			spawnOffsetY = 1.15,
			velocity = 20,
			radius = 0.1,
			onProjectileHit = function(self, what, entity)
				-- if what ~= nil then
					-- hudPrint("Hit " .. what)
				-- end
				-- if entity ~= nil then
					-- hudPrint("Entity " .. entity.name)
				-- end
				local damage = 15
				if entity == party then
					-- hudPrint("Hit the party!")
					local i = math.random(1,4)
					local champ = party.party:getChampionByOrdinal(i)
					champ:playDamageSound()
					champ:damage(rollDamage(damage), "physical")
					if math.random() < 0.5 then
						champ:setCondition("poison")
					end
				elseif entity == nil then
					playSound("impact_arrow")
				elseif entity.monster ~= nil then
					-- hudPrint("Hit monster")
					damageTile(entity.level, entity.x, entity.y, 0, entity.elevation, DamageFlags.Impact, "poison", rollDamage(damage))
					if math.random() < 0.9 then
						entity.monster:setCondition("poisoned")
					end
				else
					playSound("impact_arrow")
				end
				self.go:spawn("dart")
			end
		},
	},
}
Crypt of Zulfar
User avatar
AndakRainor
Posts: 674
Joined: Thu Nov 20, 2014 5:18 pm

Re: Having some trouble with shootProjectile

Post by AndakRainor »

I copied your examples to make a spell launching multiple falling rocks in front of the party. There still is one thing I don't know how to implement, how would you use the delayedCall function in this code to avoid throwing all rocks at the same time ? The syntax I used isn't working at all...

Code: Select all

defineObject{
   name = "rock_fall_spell",
   baseObject = "base_spell",
   components = {
      {
         class = "Model",
         model = "assets/models/items/rock.fbx",
         rotation = vec(0, 0, 0),
      },
      {
         class = "Projectile",
         spawnOffsetY = 3,
         velocity = 0,
         gravity = 10,
         radius = 0.1,
         onProjectileHit = function(self, what, entity)
            local damage = 15
            if entity == party then
               -- hudPrint("Hit the party!")
               local i = math.random(1,4)
               local champ = party.party:getChampionByOrdinal(i)
               champ:playDamageSound()
               champ:damage(rollDamage(damage), "physical")
            elseif entity == nil then
               playSound("impact_blunt")
            elseif entity.monster ~= nil then
               -- hudPrint("Hit monster")
               damageTile(entity.level, entity.x, entity.y, 0, entity.elevation, DamageFlags.Impact, "physical", rollDamage(damage))
            else
               playSound("impact_blunt")
            end
            --self.go:spawn("rock")
         end
      },
   },
}

defineSpell{
   name = "test",
   uiName = "Test",
   skill = "concentration",
   requirements = {"concentration", 1},
   gesture = 2,
   manaCost = 0,
   icon = 72,
   spellIcon = 13,
   description = "Throws something",
   onCast = function(champion, x, y, direction, elevation, skillLevel)
      if direction == 0 then y = y-1 else if direction == 1 then x = x+1 else if direction == 2 then y = y+1 else x = x-1 end end end
      local function rock_fall()
        spawn("rock_fall_spell",party.level,x-0.5+math.random(),y-0.5+math.random(),direction,elevation)
      end
      for i = 0, 5, 1 do
        --delayedCall("rock_fall", i, "rock_fall")
        rock_fall()
      end
   end
}
MrChoke
Posts: 324
Joined: Sat Oct 25, 2014 7:20 pm

Re: Having some trouble with shootProjectile

Post by MrChoke »

AndakRainor wrote:I copied your examples to make a spell launching multiple falling rocks in front of the party. There still is one thing I don't know how to implement, how would you use the delayedCall function in this code to avoid throwing all rocks at the same time ? The syntax I used isn't working at all...

Code: Select all

defineObject{
   name = "rock_fall_spell",
   baseObject = "base_spell",
   components = {
      {
         class = "Model",
         model = "assets/models/items/rock.fbx",
         rotation = vec(0, 0, 0),
      },
      {
         class = "Projectile",
         spawnOffsetY = 3,
         velocity = 0,
         gravity = 10,
         radius = 0.1,
         onProjectileHit = function(self, what, entity)
            local damage = 15
            if entity == party then
               -- hudPrint("Hit the party!")
               local i = math.random(1,4)
               local champ = party.party:getChampionByOrdinal(i)
               champ:playDamageSound()
               champ:damage(rollDamage(damage), "physical")
            elseif entity == nil then
               playSound("impact_blunt")
            elseif entity.monster ~= nil then
               -- hudPrint("Hit monster")
               damageTile(entity.level, entity.x, entity.y, 0, entity.elevation, DamageFlags.Impact, "physical", rollDamage(damage))
            else
               playSound("impact_blunt")
            end
            --self.go:spawn("rock")
         end
      },
   },
}

defineSpell{
   name = "test",
   uiName = "Test",
   skill = "concentration",
   requirements = {"concentration", 1},
   gesture = 2,
   manaCost = 0,
   icon = 72,
   spellIcon = 13,
   description = "Throws something",
   onCast = function(champion, x, y, direction, elevation, skillLevel)
      if direction == 0 then y = y-1 else if direction == 1 then x = x+1 else if direction == 2 then y = y+1 else x = x-1 end end end
      local function rock_fall()
        spawn("rock_fall_spell",party.level,x-0.5+math.random(),y-0.5+math.random(),direction,elevation)
      end
      for i = 0, 5, 1 do
        --delayedCall("rock_fall", i, "rock_fall")
        rock_fall()
      end
   end
}
The definition of delayedCall isn't worded very well in the scripting reference, nor does it have all the parameters you can pass. It says:

delayedCall(receiver, delay, msg)

receiver = The name of the script where the "delay" function resides
delay = The time to wait in seconds. You can use tenths of seconds too (i.e. 2.5).
msg = The name of the function. It must exits in the script you reference in parameter 1

Also, you can specify any number of additional parameters after these and these parameters will be passed to the delay function. The only limit is they must be basic LUA types (no game objects will work).
User avatar
AndakRainor
Posts: 674
Joined: Thu Nov 20, 2014 5:18 pm

Re: Having some trouble with shootProjectile

Post by AndakRainor »

So, here my function is local :

Code: Select all

local function rock_fall()
   spawn("rock_fall_spell",party.level,x-0.5+math.random(),y-0.5+math.random(),direction,elevation)
end
What would be the correct values for the receiver and msg parameters in this situation ?
Should I avoid using a local function ?
Where should I put the code of that function instead, and what would then be the correct values for the delayCall parameters ?
User avatar
AndakRainor
Posts: 674
Joined: Thu Nov 20, 2014 5:18 pm

Re: Having some trouble with shootProjectile

Post by AndakRainor »

Ok I found how to use delayCall properly :
the function goes into a script entity named script_center

Code: Select all

function rockFall(x, y, direction, elevation)
  spawn("rock_fall_spell",party.level,x-0.3+0.6*math.random(),y-0.3+0.6*math.random(),direction,elevation)
end
the object definition for the falling rock (multiple impacts sounds are a little annoying, what would you suggest for the sound?)

Code: Select all

defineObject{
   name = "rock_fall_spell",
   baseObject = "base_spell",
   components = {
      {
         class = "Model",
         model = "assets/models/items/rock.fbx",
         rotation = vec(0, 0, 0),
      },
      {
         class = "Projectile",
         spawnOffsetY = 3,
         velocity = 0,
         gravity = 10,
         radius = 0.1,
         onProjectileHit = function(self, what, entity)
            local damage = 5
            if entity == party then
               -- hudPrint("Hit the party!")
               local i = math.random(1,4)
               local champ = party.party:getChampionByOrdinal(i)
               champ:playDamageSound()
               champ:damage(rollDamage(damage), "physical")
            elseif entity == nil then
               --playSound("impact_generic")
            elseif entity.monster ~= nil then
               -- hudPrint("Hit monster")
               damageTile(entity.level, entity.x, entity.y, 0, entity.elevation, DamageFlags.Impact, "physical", rollDamage(damage))
            else
               --playSound("impact_generic")
            end
            --self.go:spawn("rock")
         end
      },
   },
}
and the spell definition :

Code: Select all

defineSpell{
   name = "test",
   uiName = "Test",
   skill = "concentration",
   requirements = {"concentration", 1},
   gesture = 2,
   manaCost = 0,
   icon = 72,
   spellIcon = 13,
   description = "Throws something",
   onCast = function(champion, x, y, direction, elevation, skillLevel)
      if direction == 0 then y = y-1 else if direction == 1 then x = x+1 else if direction == 2 then y = y+1 else x = x-1 end end end
      playSound("serpent_staff_launch")
      local power = champion:getCurrentStat("willpower")*skillLevel/5
      for i = 0, power, 1 do
        delayedCall("script_center", 3*i/power, "rockFall", x, y, direction, elevation)
      end
   end
}
I just noticed that the party doesn't get XP when killing a monster with this spell, do you have any idea why ?
Post Reply