Page 1 of 2

Custom Color Healing Crystals [V1.1 UPDATE]

Posted: Tue Mar 12, 2013 5:40 am
by Diarmuid
Image
Custom Color Healing Crystals Pack

Custom Crystals System, Version 1.0
Scripting & Design by Diarmuid & Neikun


Nexus Link: http://grimrock.nexusmods.com/mods/233/

This is a pack of 7 recolored healing crystals to use in your dungeon, along with a modular .lua file allowing you to define your own colors easily, and a script entity to write custom functions for different colors.

The crystals use a convoluted combination of pits, lights, altar, gratings, projectiles, item, timers, scripts... to reproduce in other colors the hardcoded animation and visuals from the normal blue healing crystal.


[[[[[ SETUP INSTRUCTIONS: ]]]]]

1. copy animations, models, scripts and textures folders to your mod_assets folder
2. add the following line at the end of your init.lua:
import "mod_assets/scripts/crystals.lua"
3. create a script_entity named crystalHandler in the dungeon editor
4. copy the contents of crystalHandler.lua into this crystalHandler script entity.
5. read readme.txt for additionnal info on how the lua scripts work.

[[[[[ CHANGELOG: ]]]]]
----------------------------------------------------------------------------------
v1.1: Fixed bug that caused hum sound to accumulate

[[[[[ THIS PACK CONTAINS: ]]]]]]

1. models and textures for the following 7 crystal colors:
----------------------------------------------------------------------------------
- green
- red
- pink
- orange
- yellow
- black
- white

TO USE THE CRYSTALS:
Simply put the dx_healing_crystal_object_"color" object in the editor like a normal crystal. That's it!

2. crystals.lua:
----------------------------------------------------------------------------------
A modular lua file which generates the crystal objects and components.

3. crystalHandler script:
----------------------------------------------------------------------------------
This must be copied in the dungeon editor in a scriptEntity named crystalHandler, and controls the crystals behaviour.


If you use this in your dungeons, please give credit back! ;)

Detailed readme.txt :
SpoilerShow
##### Custom Crystals System, Version 1.0 #####
##### Scripting & Design by Diarmuid & Neikun #####


[[[[[ SETUP INSTRUCTIONS: ]]]]]
----------------------------------------------------------------------------------
1. copy animations, models, scripts and textures folders to your mod_assets folder
2. add the following line at the end of your init.lua:
import "mod_assets/scripts/crystals.lua"
3. create a script_entity named crystalHandler in the dungeon editor
4. copy the contents of crystalHandler.lua into this crystalHandler script entity.


[[[[[ THIS PACK CONTAINS: ]]]]]]

1. models and textures for the following 7 crystal colors:
----------------------------------------------------------------------------------
- green
- red
- pink
- orange
- yellow
- black
- white

TO USE THE CRYSTALS:
Simply put the dx_healing_crystal_object_"color" object in the editor like a normal crystal. That's it!

### WARNING ###
!!! DO NOT use directly any of the crystal components that start with the | character: "|dx...".
Those objects have a red X icon and appear at the end of the objects list.
Make sure you use the ones starting with "dx_..." !!!
### WARNING ###


2. crystals.lua:
----------------------------------------------------------------------------------
A modular lua file which generates the crystal objects and components.


### WARNING ###
!!! DO NOT change anything in this file except in the Define Crystals section in the end. !!!
### WARNING ###

If you wish to add custom colors, the crystals are defined with the following syntax:

defineCrystal{
color = "green",
lightColor = {0.5,1,0.5},
particleFogColor = {0.15, 0.80, 0.35},
particleStarsColor = {1.0,4.0,1.0},
}

For the defineCrystal function to work, you must create the following files, replacing "green" with the color you want to define:
- dx_healing_crystal_green.dds (texture)
- dx_healing_crystal_shader_green.dds (texture)
- dx_healing_crystal_green.model (model, which has dx_healing_crystal_crystal_green
set as material for all 5 meshes in the GMT)
- dx_healing_crystal_shader_green.model (model, which has dx_healing_crystal_shader_green set as material in the GMT)

Use the provided models and textures as basis for your own crystals, and do not forget to add their functionnality in the
onCrystalClick function in the script entity.



3. crystalHandler script:
----------------------------------------------------------------------------------
This must be copied in the dungeon editor in a scriptEntity named crystalHandler, and controls the crystals behaviour.


By default, all crystals heal the party when clicking on them. You can however change
what the crystals do by putting your own function at the end of the crystalHandler script.

There is a global onCrystalClick(crystal) function which is called when you click an active crystal.
The crystal object is passed as a parameter, and you can use the following properties to write custom functions:

crystal.color : the color of the crystal
crystal.id : the id of the crystal entity
crystal.level /
crystal.x /
crystal.y : the position of the crystal
crystal.isActive : true/false, state of the crystal


### WARNING ###
!!! DO NOT set anything in the crystal object table, even if lua allows you to, to not break it.
Treat them as read-only properties. !!!
### WARNING ###

if you return false from onCrystalClick, you will prevent the crystal from deactivating. This can
be used to allow the crystal to be "used" only under certain conditions.

Two functions are also provided for handling crystals:

- crystalHandler.spawnCrystal(color, level, x, y, id)

color: a string with a valid defined color
level, x, y: position to spawn the crystal
id: a string with the unique id to give to the crystal

- crystalHandler.destroyCrystal(id)
id: a string with the id of the crystal to destroy

Re: Custom Color Healing Crystals [RELEASE]

Posted: Tue Mar 12, 2013 4:24 pm
by akroma222
You guys rock! Nice work :shock:

Re: Custom Color Healing Crystals [RELEASE]

Posted: Tue Mar 12, 2013 4:58 pm
by Neikun
Please let us know if you encounter any difficulty with installation, or if something in the readme is not clear.

Re: Custom Color Healing Crystals [RELEASE]

Posted: Tue Mar 12, 2013 8:35 pm
by DeDy
Installation into my basement was cool ;) Now even I play Nightfall the whole from scratch, so I tested the crystals. The first red Crystal is in my dungeon to the fifth floor. However, in the second floor, I heard the sound of silence. On the third floor was already moderately. Now I'm a bit from him, about 6 boxes at the door and can hear 2× louder than he should be. I'm still going to write and test.

Re: Custom Color Healing Crystals [RELEASE]

Posted: Tue Mar 12, 2013 10:12 pm
by Diarmuid
You mean the crystal hum sound is getting louder? Hmmm I looped the sound together with the crystal rotation. If it's longer there may be a slight accumulation effect. Does anyone know what's the crystal hum sound duration? I couldnt check as we dont have access to the sound files.

Re: Custom Color Healing Crystals [RELEASE]

Posted: Tue Mar 12, 2013 11:08 pm
by Komag
Diarmuid wrote:we dont have access to the sound files.
speak for yourself 8-)

it is exactly 5.36265 seconds long :mrgreen:

Re: Custom Color Healing Crystals [RELEASE]

Posted: Wed Mar 13, 2013 12:51 am
by Diarmuid
Komag wrote:
Diarmuid wrote:we dont have access to the sound files.
speak for yourself 8-)

it is exactly 5.36265 seconds long :mrgreen:
Oh you...

That's weird however because the sound is replayed every 14s when the crystal is activated, and it didn't stop between retriggers (?)

Re: Custom Color Healing Crystals [RELEASE]

Posted: Wed Mar 13, 2013 1:31 am
by Neikun
I know that the sound gets louder when more than one is near each other. (we're trying to mask the sound of the "pit")
The reason the crystal sound repeats itself anyway is because it loops by definition.

If this is causing a problem, we could define a new one that doesn't loop, and is played again based on a timer.

Re: Custom Color Healing Crystals [RELEASE]

Posted: Wed Mar 13, 2013 2:13 am
by Diarmuid
Ok, we found what the problem is, and will fix it. I didn't know the sound looped by itself, so it is being respawned every 14 seconds (the time of the crystal rotation). So after 10 minutes, you have 40 sounds playing at the same time :!: :roll:

Meanwhile, here's an updated crystalHandler script (1.1beta) which doesn't have the added sound looping bug: (but the sound continues to play while the crystal is off - we're working on it)
SpoilerShow

Code: Select all

--[[

#####    Crystal Handler Script, Version 1.1Beta #####
#####  Scripting & Design by Diarmuid & Neikun   #####

Setup instructions:
Copy the contents of this file in your dungeon a script entity named crystalHandler.

]]


crystalObjects = {}

-- *****************************************************************************************
--                                    CRYSTAL FUNCTIONS
-- *****************************************************************************************

function createCrystals()

	for level = 1, getMaxLevels() do

		for x = 0,31 do
			
			for y = 0,31 do
				
				for i in entitiesAt(level, x, y) do
					
					if string.find(i.name, "dx_healing_crystal_object_") then
						
						local color = string.sub(i.name, 27)
						spawnCrystal(color, level, x, y, i.id)
						
					end
				
				end
			
			end
		
		end
	
	end
	
end


function spawnCrystal(color, level, x, y, id)

	if crystalObjects[id] then
		print("Warning: crystal id already in use!")
		return false
	end
	
	-- Create crystal lua object and IDs
	crystalObjects[id] = {}
	local crystal = crystalObjects[id]
	crystal.color = color
	crystal.id = id
	crystal.level = level
	crystal.x = x
	crystal.y = y
	crystal.activated = crystal.id.."_activated"
	crystal.deactivated = crystal.id.."_deactivated"
	crystal.lights = {}
	crystal.dimLights = {}
	crystal.gratings = {}
	for j = 0, 3 do
		crystal.lights[j] = crystal.id.."_light_"..j
		crystal.dimLights[j] = crystal.id.."_dimLight_"..j
		crystal.gratings[j] = crystal.id.."_grating_"..j
	end
	crystal.topLight = crystal.id.."_topLight"
	crystal.bottomLight = crystal.id.."_bottomLight"
	crystal.particleSystem = crystal.id.."_particleSystem"
	crystal.altar = crystal.id.."_altar"
	crystal.timer = crystal.id.."_timer"
	crystal.fakeItem = crystal.id.."_fakeItem"
	crystal.animTimerActivated = crystal.id.."_animTimer1"
	crystal.animTimerDeactivated = crystal.id.."_animTimer2"
	
	-- Set it to active
	crystal.isActive = true
	
	-- Spawn activated state
	spawn("|dx_healing_crystal_"..crystal.color, level, x, y, 0, crystal.activated)
		:addTrapDoor()
		:setPitState("open")
		:close()
							
	-- Play crystal sounds
	for j = 0, 3 do
		local dx, dy = getForward(j)
		playSoundAt("crystal_ambient", level, x+dx, y+dy)
	end
	
	-- Spawn shader projectile and register ID
	crystal.shader = shootProjectileWithId("|dx_healing_crystal_shader_"..crystal.color,level,x,y,0,0,0,0,0,14,0,0,party,true)
	
	-- Spawn lights & particles lightsources
	for j = 0,3 do
		spawn("|dx_healing_crystal_light_"..crystal.color, level, x, y, j, crystal.lights[j])
		spawn("|dx_healing_crystal_light_deactivated_"..crystal.color, level, x, y, j, crystal.dimLights[j]):deactivate()
	end
	spawn("|dx_healing_crystal_top_light_"..crystal.color, level, x, y, 0, crystal.topLight)
	spawn("|dx_healing_crystal_bottom_light_"..crystal.color, level, x, y, 0, crystal.bottomLight)
	
	spawn("|dx_healing_crystal_particleSystem_"..crystal.color, level, x, y, 0, crystal.particleSystem)
	
	-- Spawn altar and fake item
	spawn("|dx_healing_crystal_altar", level, x, y, 0, crystal.altar)
		:addItem(spawn("|dx_healing_crystal_fake_item",nil,nil,nil,nil,crystal.fakeItem))
		:addConnector("deactivate", "crystalHandler", "useCrystal")
		
	-- Spawn crystal timers
	spawn("timer", level, x, y, 0, crystal.timer)
		:setTimerInterval(120)
		:addConnector("activate", "crystalHandler", "reactivateCrystal")
	spawn("timer", level, x, y, 0, crystal.animTimerActivated)
		:setTimerInterval(14)
		:addConnector("activate", "crystalHandler", "crystalAnimation")
		:activate()
	spawn("timer", level, x, y, 0, crystal.animTimerDeactivated)
		:setTimerInterval(40)
		:addConnector("activate", "crystalHandler", "crystalAnimation")
		
	-- Spawn gratings
	for j = 0, 3 do
		spawn("|dx_healing_crystal_grating", level, x, y, j, crystal.gratings[j])
	end
	
end

function destroyCrystal(id)
	
	if crystalObjects[id] then
	
		local crystal = crystalObjects[id]
		
		if crystal.isActive then
			findEntity(crystal.activated):destroy()
			findEntity(crystal.shader):destroy()
		else
			findEntity(crystal.deactivated):destroy()
		end		
		for i = 0,3 do
			findEntity(crystal.lights[i]):destroy()
			findEntity(crystal.dimLights[i]):destroy()
			findEntity(crystal.gratings[i]):destroy()
		end
		findEntity(crystal.topLight):destroy()
		findEntity(crystal.bottomLight):destroy()
		findEntity(crystal.particleSystem):destroy()
		findEntity(crystal.altar):destroy()
		findEntity(crystal.fakeItem):destroy()
		findEntity(crystal.timer):destroy()
		findEntity(crystal.animTimerActivated):destroy()
		findEntity(crystal.animTimerDeactivated):destroy()
		
		crystal = nil
		
	end
	
end


function crystalAnimation(timer)

	-- Retrieve crystal lua object by extracting its id from the timer id
	local crystal = crystalObjects[string.sub(timer.id,0,-12)]
	local level, x, y = timer.level, timer.x, timer.y
	
	if crystal.isActive == true then
	
		if findEntity(crystal.activated) then
		
			findEntity(crystal.activated):setPitState("open")
			findEntity(crystal.activated):close()
			
		else
		
			findEntity(crystal.deactivated):destroy()
			
			-- Spawn deactivated state
			spawn("|dx_healing_crystal_"..crystal.color, level, x, y, 0, crystal.activated)
				:addTrapDoor()
				:setPitState("open")
				:close()
				
			findEntity(crystal.animTimerActivated):activate()
			findEntity(crystal.animTimerDeactivated):deactivate()
		
		end
		
	else
	
		if findEntity(crystal.activated) then
		
			findEntity(crystal.activated):destroy()
			
			-- Spawn deactivated state
			spawn("|dx_healing_crystal_deactivated_"..crystal.color, level, x, y, 0, crystal.deactivated)
				:addTrapDoor()
				:setPitState("open")
				:close()
			
			findEntity(crystal.animTimerDeactivated):activate()
			findEntity(crystal.animTimerActivated):deactivate()
			
		else
		
			findEntity(crystal.deactivated):setPitState("open")
			findEntity(crystal.deactivated):close()
		
		end
		
	end

end


function useCrystal(altar)
		
	-- Retrieve crystal lua object by extracting its id from the altar id
	local crystal = crystalObjects[string.sub(altar.id,0,-7)]
	local level, x, y = altar.level, altar.x, altar.y	
	
	-- Respawn item on altar
	setMouseItem(nil)
	altar:addItem(spawn("|dx_healing_crystal_fake_item",nil,nil,nil,nil,crystal.fakeItem))
	
	-- Call Crystal Hook
	local returnValue = onCrystalClick(crystal)
	
	if returnValue == false then
		return false
	end
		
	if crystal.isActive then
			
		-- Turn off activated state lights and turn on deactivated state lights
		for i = 0,3 do
			findEntity(crystal.lights[i]):deactivate()
			findEntity(crystal.dimLights[i]):activate()
		end
		findEntity(crystal.topLight):deactivate()
		findEntity(crystal.bottomLight):deactivate()
		
		-- Turn off particle system
		findEntity(crystal.particleSystem):deactivate()
		
		-- Spawn fadeout partile system
		spawn("fx", altar.level, altar.x, altar.y, 0)
			:setParticleSystem("dx_healing_crystal_fade_"..crystal.color)
			:setLight(0,0,0,1,0,8,false)
		
		-- Destroy shader projectile
		findEntity(crystal.shader):destroy()

		-- Start timer
		findEntity(crystal.id.."_timer"):activate()
		
		-- Deactivate crystal
		crystal.isActive = false
	
	end
	
end


function reactivateCrystal(timer)

	-- Retrieve crystal lua object by extracting its id from the timer id
	local crystal = crystalObjects[string.sub(timer.id,0,-7)]
	local level, x, y = timer.level, timer.x, timer.y
		
	-- Turn off deactivated state lights and turn on activated state lights
	for i = 0,3 do
		findEntity(crystal.lights[i]):activate()
		findEntity(crystal.dimLights[i]):deactivate()
	end
	findEntity(crystal.topLight):activate()
	findEntity(crystal.bottomLight):activate()
	
	-- Turn on particle system
	findEntity(crystal.particleSystem):activate()

	-- Spawn shader projectile and register ID
	crystal.shader = shootProjectileWithId("|dx_healing_crystal_shader_"..crystal.color,level,x,y,0,0,0,0,0,14,0,0,party,true)

	-- Stop timer
	findEntity(crystal.id.."_timer"):deactivate()
	
	-- Reactivate crystal
	crystal.isActive = true
	
end

function cancelAltar(altar)

	for i in altar:containedItems() do
	
		if i.name ~= "|dx_healing_crystal_fake_item" then
			setMouseItem(spawn(i.name))
			i:destroy()
		end
		
	end
	
end


-- *****************************************************************************************
--                                    HELPER FUNCTIONS
-- *****************************************************************************************

function shootProjectileWithId(projName,level,x,y,dir,speed,gravity,velocityUp,offsetX,offsetY,offsetZ,attackPower, ignoreEntity,fragile,championOrdinal)
	local pIds = {}
	
	for i in entitiesAt(level, x, y) do
		if i.class == "Item" and string.find(i.id, "^%d+$") then
			pIds[i.id] = i.name
		end
	end
	
	shootProjectile(projName,level,x,y,dir,speed,gravity,velocityUp,offsetX,offsetY,offsetZ,attackPower, ignoreEntity,fragile,championOrdinal)
 	
	for i in entitiesAt(level, x, y) do
		if i.class == "Item" and string.find(i.id, "^%d+$") and not(pIds[i.id]) then
			return i.id
		end
	end  

end

-- *****************************************************************************************
--                                           INIT
-- *****************************************************************************************

createCrystals()

-- *****************************************************************************************
--                                  CUSTOM CRYSTAL FUNCTIONS
-- *****************************************************************************************


function onCrystalClick(crystal)
	
	if crystal.isActive and crystal.color == "green" then
	
		party:heal()
		
	end
	
	if crystal.isActive and crystal.color == "pink" then
	
		party:heal()
		
	end

	if crystal.isActive and crystal.color == "red" then
	
		party:heal()
		
	end

	if crystal.isActive and crystal.color == "black" then
	
		party:heal()
		
	end

	if crystal.isActive and crystal.color == "orange" then
	
		party:heal()
		
	end	
	
	if crystal.isActive and crystal.color == "yellow" then
	
		party:heal()
		
	end	
	
	if crystal.isActive and crystal.color == "white" then
	
		party:heal()
		
	end	
end


Re: Custom Color Healing Crystals [RELEASE]

Posted: Wed Mar 13, 2013 8:54 am
by Grimfan
Great job all around guys, though you can still clearly hear the pit opening sound sometimes (when I first heard it I thought one of my pits on the level was being set off by itself). Still, this is excellent work. :D