Page 377 of 396

Re: Ask a simple question, get a simple answer

Posted: Thu Jun 03, 2021 7:51 pm
by Isaac
This doesn't work for maps with non-default water elevations.

*And doesn't detect if they are in the water. ( ?)

(Though it could work reasonably well on default overland maps. 8-) )

Re: Ask a simple question, get a simple answer

Posted: Fri Jun 04, 2021 1:19 am
by 7Soul
Yeah I didn't have to check if they were actually in the water because usually you won't have solid ground in a part of the map that's below the water in another section of the same map. So checking if you're below the level of any watersurface in the map was enough

Then I guess you could do waterLevel = entity:getWorldPositionY() - 0.4 instead of the -0.6 so it works for water that isn't at height 0

Re: Ask a simple question, get a simple answer

Posted: Fri Jun 04, 2021 3:34 am
by Isaac
Here is a map with water at level zero:

https://player.vimeo.com/video/335643649

Your method would work with it, but (also) its only submerged area is a type 2 water tile. So being on that tile means they are under water.

*Yet another way to detect a party under water (suitable for small areas) is to simply to place underwater floor_triggers that only activate for the party; and check if they are pressed.

Re: Ask a simple question, get a simple answer

Posted: Fri Jun 04, 2021 8:27 am
by Lorial
Thanks for the replies, but the whole underwater bit just makes my head hurt and nothing seems to work. Gonna leave that to those who know what they're doing.
Zo Kath Ra wrote: Thu Jun 03, 2021 9:50 am Or you can attach timers to the party dynamically:
http://www.grimrock.net/forum/viewtopic ... 23#p121823
Just to clarify things: With the party object and the timer attached I now have a global timer running "in the background", right? So whenever I connect timer objects with scripts for respawn and individual timers for each of those, I get to use numerous timers simultaneously?
Are there any known downsides to this when used in huge mods, such as lag or crashes or the likes? And does a reload of the game reset the timer or is its progress saved? This would be especially important for long timers, such as 3600 or 7200 second ones.


I am still trying to turn levers and buttons unclickable after a single use, the below only allows for disableSelf on a button, but it is still animated. It does work with scripts for individual objects like "wall_button_1.clickable:disable()", but I cannot get it to work on the item definition to have it click into place by default if the disableSelf box is ticked.
SpoilerShow

Code: Select all

defineObject{
	name = "wall_button",
	baseObject = "wall_button",
	components = {
		{
			class = "Button",
			sound = "button",
			onActivate = function(self)
				return self:isEnabled()
			end,
		},
	}
}

Re: Ask a simple question, get a simple answer

Posted: Fri Jun 04, 2021 9:58 am
by Isaac

Code: Select all


defineObject{
	name = "wall_button",
	baseObject = "wall_button",
	components = {
		{
			class = "Button",
			sound = "button",
			onActivate = function(self) 
				local enabled = self:isEnabled()
				if not enabled then 
					self.go.clickable:disable()
				end
				return enabled
			end,
		},
	}
}




Re: Ask a simple question, get a simple answer

Posted: Fri Jun 04, 2021 1:08 pm
by Zo Kath Ra
Lorial wrote: Fri Jun 04, 2021 8:27 am Just to clarify things: With the party object and the timer attached I now have a global timer running "in the background", right? So whenever I connect timer objects with scripts for respawn and individual timers for each of those, I get to use numerous timers simultaneously?
Are there any known downsides to this when used in huge mods, such as lag or crashes or the likes? And does a reload of the game reset the timer or is its progress saved? This would be especially important for long timers, such as 3600 or 7200 second ones.
> With the party object and the timer attached I now have a global timer running "in the background", right?

You'll have a timer that's always running.
They'll probably work even when the party is resting, but I haven't tried this yet.

> So whenever I connect timer objects with scripts for respawn and individual timers for each of those, I get to use numerous timers simultaneously?

As long as the timer components have different names, you can have as many as you need.

> Are there any known downsides to this when used in huge mods, such as lag or crashes or the likes?

Maybe if there are thousands of timers, and they all have a timer interval of 0.
But if your timers only fire once per hour, there shouldn't be a problem.
If your timers negatively affect performance, you can move all code into a single timer, and keep a table of countdowns.
Or you can disable all timers, and start them manually, with their starting times offset slightly. This will prevent them from all activating at the same time.

> And does a reload of the game reset the timer or is its progress saved?

The progress is saved, otherwise some puzzles wouldn't work.

Re: Ask a simple question, get a simple answer

Posted: Sat Jun 05, 2021 7:14 am
by Lorial
Thank you so much for that, Isaac.
Unfortunately, this leaves it clickable twice, even though the second click does nothing (tested with toggles). Fiddled around a bit and I now have a single-use button, just like I wanted. However, the disableSelf box has no effect. So now there are three versions.

1) Single activation if disableSelf is checked, remains clickable:
SpoilerShow

Code: Select all

defineObject{
	name = "wall_button",
	baseObject = "wall_button",
	components = {
		{
			class = "Button",
			sound = "button",
			onActivate = function(self)
				return self:isEnabled()
			end,
		},
	}
}
2) Single activation if disableSelf is checked, clickable twice (confusing):
SpoilerShow

Code: Select all

defineObject{
	name = "wall_button_disable",
	baseObject = "wall_button",
	components = {
		{
			class = "Button",
			sound = "button",
			onActivate = function(self) 
				local enabled = self:isEnabled()
				if not enabled then 
					self.go.clickable:disable()
				end
				return enabled
			end,
		},
	}
}
3) Single use, disregarding disableSelf box:
SpoilerShow

Code: Select all

defineObject{
	name = "wall_button_single",
	baseObject = "wall_button",
	components = {
		{
			class = "Button",
			sound = "button",
			onActivate = function(self)
				if not enabled then 
					self.go.clickable:disable()
				end
			end,
		},
	}
}

The ideal version would, of course, be a single interaction/click when disableSelf is checked, but I can't figure it out. What am I missing?!

Zo Kath Ra wrote: Fri Jun 04, 2021 1:08 pm You'll have a timer that's always running.
They'll probably work even when the party is resting, but I haven't tried this yet.[...]
Thanks for clearing that up, Zo Kath Ra. Time to put it to good use, no pun intended.

Re: Ask a simple question, get a simple answer

Posted: Sat Jun 05, 2021 10:35 am
by Zo Kath Ra
Lorial wrote: Sat Jun 05, 2021 7:14 am Thank you so much for that, Isaac.
Unfortunately, this leaves it clickable twice, even though the second click does nothing (tested with toggles). Fiddled around a bit and I now have a single-use button, just like I wanted. However, the disableSelf box has no effect. So now there are three versions.
If you want the Button component's disableSelf checkbox to have an effect, you need to look at its value.

Code: Select all

defineObject{
	baseObject = "wall_button",
	name = "wall_button_new",
	components = {
		{
			class = "Button",
			sound = "button",
			onActivate = function(self)
				print(self.go.id, "onActivate")
				print(self.go.id, "isEnabled", self:isEnabled())
				if self:getDisableSelf() then
					self.go.clickable:disable()
				end
				return self:isEnabled()
			end,
		},
	},
}

Re: Ask a simple question, get a simple answer

Posted: Sun Jun 06, 2021 9:14 pm
by Lorial
Zo Kath Ra wrote: Sat Jun 05, 2021 10:35 am If you want the Button component's disableSelf checkbox to have an effect, you need to look at its value.
Perfect, works like a charm and for all buttons, secret buttons and levers. Now disableSelf is finally working as intended. Now off to removing all the scripts for individual buttons, yay. Thanks again, Zu Kath Ra.

Re: Ask a simple question, get a simple answer

Posted: Sat Jun 19, 2021 8:00 am
by bongobeat
coucou there,
I wonder if you can help to resolve this:

I got an issue with a monster/and it's attack, it can crash the game after it spawns its shock attacks all around:

here is the error message that I got in the editor: in this case the monster was on the ground, and I stood 2 heights above.
SpoilerShow
Image
this is the line mentionned in the screen (and the whole function):
SpoilerShow

Code: Select all

			onAttack = function(self)
				local x,y = self.go.x,self.go.y
				local dx,dy = getForward(self.go.facing)
				x = x + dx
				y = y + dy
				spawn("shock_wave", self.go.level, x, y, 0, self.go.elevation)
				party.party:shakeCamera(0.7, 0.3)
			end,
This is the complete monster script:
SpoilerShow

Code: Select all

defineObject{
	name = "redrock_golem",
	baseObject = "base_monster",
	components = {
		{
			class = "Model",
			model = "assets/models/monsters/magma_golem.fbx",
			material = "mountain_wall_01",
			storeSourceData = true, -- must be enabled for mesh particles to work
		},
		{
			class = "Animation",
			animations = {
				idle = "assets/animations/monsters/magma_golem/magma_golem_idle.fbx",
				moveForward = "assets/animations/monsters/magma_golem/magma_golem_walk.fbx",
				turnLeft = "assets/animations/monsters/magma_golem/magma_golem_turn_left.fbx",
				turnRight = "assets/animations/monsters/magma_golem/magma_golem_turn_right.fbx",
				turnAround = "assets/animations/monsters/magma_golem/magma_golem_turn_around.fbx",
				attack = "assets/animations/monsters/magma_golem/magma_golem_attack.fbx",
				attack2 = "assets/animations/monsters/magma_golem/magma_golem_punch_attack.fbx",
				groundPound = "assets/animations/monsters/magma_golem/magma_golem_ground_pound.fbx",
				rangedAttack = "assets/animations/monsters/magma_golem/magma_golem_ranged_attack.fbx",
				turnAttackLeft = "assets/animations/monsters/magma_golem/magma_golem_turn_attack_left.fbx",
				turnAttackRight = "assets/animations/monsters/magma_golem/magma_golem_turn_attack_right.fbx",
				getHitFrontLeft = "assets/animations/monsters/magma_golem/magma_golem_get_hit_front_left.fbx",
				getHitFrontRight = "assets/animations/monsters/magma_golem/magma_golem_get_hit_front_right.fbx",
				getHitBack = "assets/animations/monsters/magma_golem/magma_golem_get_hit_back.fbx",
				getHitLeft = "assets/animations/monsters/magma_golem/magma_golem_get_hit_left.fbx",
				getHitRight = "assets/animations/monsters/magma_golem/magma_golem_get_hit_right.fbx",
				fall = "assets/animations/monsters/magma_golem/magma_golem_get_hit_front_left.fbx",
				meteorFall = "assets/animations/monsters/magma_golem/magma_golem_meteor.fbx",
			},
			currentLevelOnly = true,
			onAnimationEvent = function(self, event)
				if event == "footstep" then
					if self.go.brain.partyOnLevel then
						local dist = math.abs(party.x - self.go.x) + math.abs(party.y - self.go.y)
						if dist < 5 then 
							party.party:shakeCamera(0.7 / dist, 0.3)
						end
					end
				end
			end,
		},
		{
			class = "Monster",
			meshName = "stone_elemental_mesh",
			hitSound = "magma_golem_hit",
			dieSound = "magma_golem_die",
			footstepSound = "magma_golem_footstep",
			hitEffect = "hit_flame",
			capsuleHeight = 0.2,
			capsuleRadius = 0.7,
			collisionRadius = 1.5,
			collisionHeight = 2.5,
			health = 3000,
			protection = 70,
			evasion = -10,
			exp = 2000,
			lootDrop = { 100, "red_rock", 60, "red_rock", 40, "red_rock", 20, "red_rock", 10, "red_rock" },
			immunities = { "sleep", "blinded", "knockback", "frozen", "poisoned" },
			resistances = {
				shock = "immune",
				fire = "weak",
				frost = "resist",
				poison = "immune",
			},
			traits = { "elemental" },
		},
		{
			class = "MagmaGolemBrain",
			name = "brain",
			sight = 30,
			morale = 100,
		},
		{
			class = "MonsterMove",
			name = "move",
			sound = "magma_golem_walk",
			cooldown = 3,
		},
		{
			class = "MonsterTurn",
			name = "turn",
			sound = "magma_golem_walk",
		},
		{
			class = "MonsterAttack",
			name = "basicAttack",
			animation = "attack",
			attackPower = 110,
			woundChance = 40,
			cooldown = 2,
			sound = "magma_golem_attack",
			onBeginAction = function(self)
				-- randomize animation
				if math.random() < 0.5 then
					self:setAnimation("attack")
				else
					self:setAnimation("attack2")
				end
			end,
		},
		{
			class = "MonsterAttack",
			name = "turnAttack",
			attackPower = 140,
			cooldown = 3,
			sound = "magma_golem_turn_attack",
			accuracy = 70,
			woundChance = 40,
			turnToAttackDirection = true,
			cameraShake = true,
			cameraShakeIntensity = 0.7,
			screenEffect = "damage_screen",
		},
		{
			class = "MonsterAttack",
			name = "groundPound",
			animation = "groundPound",
			cooldown = 10,
			repeatChance = 0,
			sound = "magma_golem_ground_pound",
			onAttack = function(self)
				local x,y = self.go.x,self.go.y
				local dx,dy = getForward(self.go.facing)
				x = x + dx
				y = y + dy
				spawn("shock_wave", self.go.level, x, y, 0, self.go.elevation)
				party.party:shakeCamera(0.7, 0.3)
			end,
		},
		{
			class = "MonsterAttack",
			name = "rangedAttack",
			attackType = "projectile",
			cooldown = 5,
			animation = "rangedAttack",
			sound = "magma_golem_ranged_attack",
			onBeginAction = function(self)
				self.go.spitParticle:restart()
			end,
			onAttack = function(self)
				local projectile = self.go.monster:shootProjectile("redrock2_meteor", 3, 10, "jaw").projectile
				projectile:setVelocity(15)
				projectile:setGravity(16)
				projectile:setIgnoreEntity(self.go, 1)
				local dist = self.go.brain.partyDistY
				if dist < 3 then
					projectile:setFallingVelocity(0.1)
					projectile:setVelocity(10)
				elseif dist == 3 then
					projectile:setFallingVelocity(1)
				elseif dist == 4 then
					projectile:setFallingVelocity(2.7)
				elseif dist == 5 then
					projectile:setFallingVelocity(5.5)
				else
					projectile:setFallingVelocity(7.5)
				end

				return false
			end,
		},
		{
			class = "Particle",
			name = "spitParticle",
			parentNode = "jaw",
			particleSystem = "redrock_golem_spit",
			offset = vec(0, 0, 0.1),
			enabled = false,
		},
	},
}
It is actually a copy of the magma golem monster, except it does shock damage.

Here are the spawned objects:
The shock_wave:
SpoilerShow

Code: Select all

defineObject{
	name = "shock_wave",
	baseObject = "base_spell",
	components = {
		{
			class = "Blast",
			delay = 0.2,
			effect = "shockburst",
		}
	}
}
----------------------------------------------------------
----- long range attack --------------------------
SpoilerShow

Code: Select all

defineParticleSystem{
	name = "redrock_golem_spit",
	emitters = {
		-- 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 = {0.7, 0.7},
			colorAnimation = false,
			color0 = {0.25, 0.5, 1},
			opacity = 0.2,
			fadeIn = 0.4,
			fadeOut = 0.5,
			size = {2, 2},
			gravity = {0,0,0},
			airResistance = 1,
			rotationSpeed = 2,
			blendMode = "Additive",
			objectSpace = true,
			depthBias = 0.2,
		},
		-- 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.7, 0.7},
			colorAnimation = false,
			color0 = {0.25, 0.5, 1},
			opacity = 1,
			fadeIn = 0.3,
			fadeOut = 0.5,
			size = {0.6, 0.6},
			gravity = {0,0,0},
			airResistance = 1,
			rotationSpeed = 2,
			blendMode = "Additive",
			objectSpace = true,
			depthBias = 0.2,
		}
	}
}

defineObject{
	name = "redrock2_meteor",
	baseObject = "base_spell",
	components = {
		{
			class = "Particle",
			particleSystem = "lightning_bolt_greater",
		},
		{
			class = "Light",
			color = vec(0.25, 0.5, 1),
			brightness = 15,
			range = 7,
			castShadow = true,
			fillLight = true,
		},
		{
			class = "Sound",
			sound = "lightning_bolt",
		},
		{
			class = "Sound",
			name = "launchSound",
			sound = "lightning_bolt_launch",
		},
		{
			class = "Projectile",
			spawnOffsetY = 1.35,
			velocity = 10,
			radius = 0.1,
			hitEffect = "redrockgolem_blast",
			onProjectileHit = function(self, what, entity)
				local x,y,level,map = self.go.x,self.go.y,self.go.level,self.go.map
				local elevation = map:getElevation(x, y)

				spawn("shock_fire", level, x, y, 0, elevation)
				if y > 0 then spawn("shock_fire", level, x, y-1, 0, elevation) end
				if y < map:getHeight() - 1 then spawn("shock_fire", level, x, y+1, 1, elevation) end
				if x > 0 then spawn("shock_fire", level, x-1, y, 2, elevation) end
				if x < map:getWidth() - 1 then spawn("shock_fire", level, x+1, y, 3, elevation) end
			end,
		},
	},
}
Originaly, its spawned a mini monster on the hit, instead of the shock_fire object, I removed that for testing, after a crash report. I thought that this can come from spawning a monster, in an obstacle or wall.

the shock fire effect:
Object:
SpoilerShow

Code: Select all

defineObject{
	name = "shock_fire",
	baseObject = "base_spell",
	components = {
		{
			class = "Model",
--			model = "mod_assets/models/wall_fire2.fbx",
			model = "assets/models/effects/wall_fire.fbx",
			materialOverrides = { ["flame_streak"] = "flame_streak2", ["fire_puddle"] = "fire_puddle2" },
			sortOffset = 1,
		},
		{
			class = "Animation",
			animations = {
				idle = "assets/animations/effects/wall_fire.fbx",
			},
			playOnInit = "idle",
			onAnimationEvent = function(self, event)
				if event == "end" then
					self.go.particle:stop()
					self.go.particle2:stop()
					self.go.particle:fadeOut(1)
					self.go.particle2:fadeOut(1)
					self.go.light:fadeOut(1)
				end
			end,
		},
		{
			class = "Particle",
			particleSystem = "wall_fire_smoke",
			offset = vec(0, 0, 0),
			sortOffset = 3,
			--destroyObject = true,
		},
		{
			class = "Particle",
			name = "particle2",
			particleSystem = "shock_fire",
			offset = vec(0, 0, 0),
			--destroyObject = true,
		},
		{
			class = "Particle",
			name = "impact",
			particleSystem = "shock_fire_impact",
			offset = vec(0, 0, 0),
			sortOffset = 3,
			--destroyObject = true,
		},
		{
			class = "Light",
			color = vec(0.25, 0.4, 1.25),
			brightness = 35,
			range = 6,
			offset = vec(0, 1.2, 0),
			--fadeOut = 0.75,
			disableSelf = true,
		},
		{
			class = "TileDamager",
			attackPower = 35,
			damageType = "shock",
			repeatCount = 5,
			repeatDelay = 4.3/5,
		},
	},
}
Particle:
SpoilerShow

Code: Select all

defineParticleSystem{
	name = "shock_fire",
	emitters = {
		-- glow
		{
			spawnBurst = true,
			emissionRate = 1,
			emissionTime = 0,
			maxParticles = 1,
			boxMin = {0, 1, 0},
			boxMax = {0, 1, 0},
			sprayAngle = {0,30},
			velocity = {0,0},
			texture = "assets/textures/particles/glow_ring.tga",
			lifetime = {1000, 1000},
			colorAnimation = false,
			color0 = {0.090000, 0.495000, 1.500000},
			opacity = 0.1,
			fadeIn = 0.01,
			fadeOut = 0.5,
			size = {7, 7},
			gravity = {0,0,0},
			airResistance = 1,
			rotationSpeed = 0,
			blendMode = "Additive",
		},

		-- sparkles
		{
			emissionRate = 200,
			emissionTime = 0,
			maxParticles = 300,
			boxMin = {-1.3, -0.3,-1.3 },
			boxMax = { 1.3,  1.5, 1.3 },
			sprayAngle = {0,180},
			velocity = {0.1,0.5},
			objectSpace = false,
			texture = "assets/textures/particles/force_field_particle.tga",
			lifetime = {0.4,1},
			color0 = {0.8*1.5,1.2*1.5,1.9*1.5},
			opacity = 1,
			fadeIn = 0.1,
			fadeOut = 0.1,
			size = {0.03, 0.1},
			gravity = {0,2.3,0},
			airResistance = 0.01,
			rotationSpeed = 10,
			blendMode = "Additive",
		},

		-- glow sparkles
		{
			emissionRate = 30,
			emissionTime = 0,
			maxParticles = 100,
			boxMin = {-1.3,  0.0,-1.3 },
			boxMax = { 1.3,  0.5, 1.3 },
			sprayAngle = {0,180},
			velocity = {0.1,0.5},
			texture = "assets/textures/particles/glow.tga",
			lifetime = {0.2, 0.6},
			colorAnimation = false,
			color0 = {0.090000, 0.495000, 1.500000},
			opacity = 1,
			fadeIn = 0.1,
			fadeOut = 0.5,
			size = {0.3, 1.8},
			gravity = {0,1.5,0},
			airResistance = 1,
			rotationSpeed = 0,
			blendMode = "Additive",
		},
	}
}

defineParticleSystem{
	name = "shock_fire_impact",
	emitters = {
		-- sparkles
		{
			spawnBurst = true,
			maxParticles = 1000,
			boxMin = {-1.3, 0.0, -1.3 },
			boxMax = { 1.3, 0.1,  1.3 },
			sprayAngle = {0,180},
			velocity = {2,5},
			objectSpace = false,
			texture = "assets/textures/particles/force_field_particle.tga",
			lifetime = {0.3,0.6},
			color0 = {0.8*1.5,1.2*1.5,1.8*1.5},
			opacity = 1,
			fadeIn = 0.01,
			fadeOut = 0.3,
			size = {0.05, 0.3},
			gravity = {0,0,0},
			airResistance = 0.01,
			rotationSpeed = 3,
			blendMode = "Additive",
		},

		-- glow sparkles
		{
			spawnBurst = true,
			maxParticles = 20,
			boxMin = {-1.3,  0.0,-1.3 },
			boxMax = { 1.3,  0.1, 1.3 },
			sprayAngle = {0,180},
			velocity = {0.1,0.5},
			texture = "assets/textures/particles/glow.tga",
			lifetime = {0.2, 0.6},
			colorAnimation = false,
			color0 = {0.090000, 0.495000, 1.500000},
			opacity = 1,
			fadeIn = 0.01,
			fadeOut = 0.5,
			size = {0.3, 1.8},
			gravity = {0,1.5,0},
			airResistance = 1,
			rotationSpeed = 0,
			blendMode = "Additive",
		},
	}
}
The blast effect:
SpoilerShow

Code: Select all

defineObject{
	name = "redrockgolem_blast",
	baseObject = "base_spell",
	components = {
		{
			class = "Particle",
			particleSystem = "redrockgolem_blasteffect",
			destroyObject = true,
		},
		{
			class = "Light",
			color = vec(0.25, 0.5, 1),
			brightness = 40,
			range = 10,
			fadeOut = 0.5,
			disableSelf = true,
			fillLight = true,
		},
		{
			class = "TileDamager",
			attackPower = 80,
			damageType = "shock",
			screenEffect = "frozen_screen",
			sound = "mortar_hit_2",
		},
	},
}

defineParticleSystem{
	name = "redrockgolem_blasteffect",
	emitters = {
		{	-- globe
			spawnBurst = true,
			maxParticles = Config.getRenderingQuality() == 1 and 512 or 4096,
			sprayAngle = {0,180},
			boxMin = {0,0,0},
			boxMax = {0,0,0},
			velocity = {40,48},
			texture = "assets/textures/particles/goromorg_lantern.tga",
			frameRate = 35,
			frameSize = 64,
			frameCount = 16,
			lifetime = {0.5, 2.5},
			colorAnimation = true,
			color0 = {1, 1, 2},
			color1 = {0.75, 0.90, 1.75},
			color2 = {0.5, 0.65, 1.25},
			color3 = {0.25, 0.5, 1},
			opacity = 1,
			fadeIn = 0.001,
			fadeOut = 0.8,
			size = {0.1, 0.3},
			gravity = {0,0,0},
			airResistance = 9,
			rotationSpeed = 1,
			blendMode = "Additive",
		},
		{	-- smoke
			emissionRate = Config.getRenderingQuality() == 1 and 64 or 1024,
			emissionTime = 0.3,
			maxParticles = 512,
			boxMin = {-5, -5, -5},
			boxMax = {5, 5, 5},
			sprayAngle = {0,100},
			velocity = {0.1, 0.5},
			texture = "assets/textures/particles/smoke_01.tga",
			lifetime = {1,4},
			color0 = {0.25, 0.5, 1},
			opacity = 1,
			fadeIn = 0.3,
			fadeOut = 0.9,
			size = {1, 3},
			gravity = {0,0,0},
			airResistance = 0.1,
			rotationSpeed = 0.5,
			blendMode = "Translucent",
		},
		{	-- not so floaty sparks
			spawnBurst = true,
			maxParticles = Config.getRenderingQuality() == 1 and 32 or 256,
			boxMin = {-1,0.1,-1},
			boxMax = {1,0.2,1},
			sprayAngle = {0,50},
			velocity = {16, 24},
			texture = "assets/textures/particles/glow.tga",
			lifetime = {1, 1.5},
			colorAnimation = true,
			color0 = {1, 2, 2},
			color1 = {0.75, 0.7, 1},
			color2 = {0.35, 0.6, 1},
			color3 = {0.25, 0.5, 1},
			opacity = 1,
			fadeIn = 0.001,
			fadeOut = 0.8,
			size = {0.04, 0.08},
			gravity = {0,-8,0},
			rotationSpeed = 1,
			airResistance = 2.6,
			blendMode = "Additive",
			depthBias = 0.006,
		},
	}
}