Scripting "Force Open" spell--intended to open doors

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
Gunsrequiem
Posts: 4
Joined: Thu Jan 17, 2013 12:11 am

Scripting "Force Open" spell--intended to open doors

Post by Gunsrequiem »

Hey all!

This will be my first post, and the primary reason I am resorting to this is because I am at a loss of ideas and need aid.

My intention is to create a spell that will allow the caster to "force open" doors in specific areas of the dungeon. I am prepared to ensure that only a specific type of door can be affected by the spell, which will make the scripting a little simpler. Furthermore, it would be best if the player needs to be within a certain distance of the door to enable the spell to affect it.

The furthest I've gotten is setting the parameters in the spells.lua:

defineSpell{

name = "open_door",
uiName = "Force Open",
skill = "spellcraft",
level = 1,
runes = "BDFH",
manaCost = 40

I'm not sure how to continue, particularly because I don't quite grasp the "onCast" function or how to affect other entities.

Any help would be greatly appreciated!

~Gun
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: Scripting "Force Open" spell--intended to open doors

Post by Diarmuid »

Hi, this is actually not a trivial task, espcially if you want to open doors from a distance, but I have it already done:
Here's the video: http://www.youtube.com/watch?v=kRtOYEHqh2s

And here's the scripting framework that makes it possible:
viewtopic.php?f=14&t=4459

Notice that it says 1.4 beta 2, if you just wait until tomorrow, I'll post the final 1.4 version tonight with a wiki and clear install instructions.

EXSP is a complex scripting framework for coders, but it's also a plug-and-play spell library that everyone can just install and use in their dungeon, no questions asked.
User avatar
Phitt
Posts: 442
Joined: Tue Aug 14, 2012 9:43 am

Re: Scripting "Force Open" spell--intended to open doors

Post by Phitt »

A more simple solution may be to use an invisible receptor you put on top of those doors that is activated by the 'Force Open' spell.
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: Scripting "Force Open" spell--intended to open doors

Post by Diarmuid »

Receptors on doors don't work, they have to be on a wall.
User avatar
Komag
Posts: 3658
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Scripting "Force Open" spell--intended to open doors

Post by Komag »

do they work if put on a wall first then moved over?
Finished Dungeons - complete mods to play
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: Scripting "Force Open" spell--intended to open doors

Post by Diarmuid »

No, tried it a long time ago, :).

The only way to detect doors is by running two entitiesAt iterators, one for each side of the door, as doors between two squares can be at any of the two coords, and filter them by facing. This is complicated by the fact that the door doesn't return its class property (bug). Here's the code I used in exsp (it's a global collision detection function, but you can take the door part out of it):

Code: Select all

function getCollisionAhead(self, level, x, y, facing)
	
	if self.id ~= "exsp" then
		if not(self) then
			return nil, nil, nil
		end
		facing = level or self.facing
		level, x, y = self:getPosition()
	end
	if not(level) then
		return nil, nil, nil
	end

	local dx, dy = getForward(facing)
	local monsters = {}
	
	-- Check for entities on current tile
	for i in entitiesAt(level, x, y) do
		if grimq.isDoor(i) and i:isClosed() and i.facing == facing then
			return "door", nil, i
		end
		if (i.class == "Alcove" or i.class == "Button" or i.class == "Decoration" 
			or i.class == "Lever" or i.class == "Lock" or i.class == "Receptor" 
			or i.class == "TorchHolder") and i.facing == facing and isWall(level, x+dx, y+dy) then
			return "wall", i.class, i
		end
	end
	
	-- Check for entities on next tile
	for i in entitiesAt(level, x+dx, y+dy) do
		if grimq.isDoor(i) and i:isClosed() and (i.facing+2)%4 == facing then
			return "door", nil, i
		end
		if i.class == "Monster" then
			table.insert(monsters, i)
		end
		if i.class == "Party" then
			return "party", nil, i
		end
		if i.class == "Blockage" or i.class == "Crystal" then
			return "object", i.class, i
		end
	end

	if isWall(level, x+dx, y+dy) then
		return "wall", nil, nil
	end
	if #monsters > 0 then
		return "monster", nil, monsters
	else
		return nil, nil, nil
	end
end
Notice that I used grimq for detecting door class, but you can find it by checking for its methods.
Gunsrequiem
Posts: 4
Joined: Thu Jan 17, 2013 12:11 am

Re: Scripting "Force Open" spell--intended to open doors

Post by Gunsrequiem »

I appreciate the fast responses!

I look forward to seeing the script, as this is a core element of my game.

EDIT: Now, is this something I need to add to the mod, or is it some script I can just copy + paste? Also, I would probably use different fx, so it would be helpful to see what the scripting is either way.

Thanks again!
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: Scripting "Force Open" spell--intended to open doors

Post by Diarmuid »

Hi gunsrequiem,

If you wish to use my prescripted open-doors spell, you need to install 2 things in your mod, the LoG framework (if you don't have it already) and the EXSP framework. It's really not complicated, 4 steps:

1. download and unzip LoGFramework.zip in your mod_assets folder: https://docs.google.com/open?id=0B7cR7s ... G1WSGJRWFU
2. put a script entity in you dungeon named logfw_init and paste this code inside:
SpoilerShow

Code: Select all

spawn("LoGFramework", party.level,1,1,0,'fwInit')
fwInit:open() 
-- timer will call this method automatically  0.1 seconds after the game is started
function main()
   fw.debug.enabled = false
   fwInit:close() --must be called
end
3. download and unzip the latest EXSP.zip in your mod_assts folder from here: https://docs.google.com/folder/d/0B-rVm ... 2Z4X25sMVU
4. import the luas in your init.lua:
import "mod_assets/framework/framework.lua" after the standard assets
import "mod_assets/exsp/exsp_init.lua" at the end of the file

Now you've got both frameworks installed!

Then, you can go in mod_assets/exsp/exsp_init.lua and enable/disbale any custom spells you wish, they are individual .lua files contained in the spells folder, a plugin-like structure. The open doors spell is mod_assets/exsp/spells/exsp_zo_spell.lua. You can just open that file and edit the spell definitions, the spell name, the spell scroll, runes, mana requirements, delete the particle effects I used and put others you want... I can help you with that if needed. :)

If you want to look at it quickly, here's what's in the open doors spell .lua:
SpoilerShow

Code: Select all

--[[ 
Spell Plugin for EXSP

Spell Name: Zo Spell
Spell Author: Diarmuid
Script Version: 1.2

Spell Readme:
This spell opens doors and is modeled after the Dungeon Master Zo spell. I've included a particle with rainbow effect similar to the original.

For runes, the Zo rune referenced the negative plane, so in LoG I equated this to the Death rune. Feel free to adjust.

Note that, to avoid this being game-breaking and allowing to freely open locked doors, only doors which have their id end with "zo" will be opened by the spell. This allows the dungeon designer to set which doors respond to this spell.

If you wish to change the spell name to something else (like "Open Door"), just change the uiName in defineSpell and scroll defineObject.

Changelog:
1.2 Updated code for exsp 1.4
1.1 Dropped deprecated onDoorHit hook in exsp 1.3.2

]]

-- ****** Define particle systems and sounds ******

defineParticleSystem{
	name = "zo_spell",
	emitters = {
		{
			emissionRate = 15,
			emissionTime = 0,
			maxParticles = 1000,
			boxMin = { 0,0,0 },
			boxMax = { 0,0,0 },
			sprayAngle = {0,360},
			velocity = {0,0},
			objectSpace = true,
			texture = "mod_assets/exsp/spells/exsp_zo_spell.tga",
			frameRate = 4,
			frameSize = 256,
			frameCount = 4,
			lifetime = {0.1,0.3},
			color0 = {1.5,1.5,1.5},
			opacity = 0.1,
			fadeIn = 0.1,
			fadeOut = 0.1,
			size = {0.125, 0.5},
			gravity = {0,0,0},
			airResistance = 5,
			rotationSpeed = 1,
			blendMode = "Additive",
		},

		-- core
		{
			emissionRate = 10,
			emissionTime = 0,
			maxParticles = 1000,
			boxMin = { 0,0,0 },
			boxMax = { 0,0,0 },
			sprayAngle = {0,360},
			velocity = {0,0},
			objectSpace = true,
			texture = "mod_assets/exsp/spells/exsp_zo_spell.tga",
			frameRate = 4,
			frameSize = 256,
			frameCount = 4,
			lifetime = {0.1,0.3},
			color0 = {1.5,1.5,1.5},
			opacity = 0.8,
			fadeIn = 0.1,
			fadeOut = 0.1,
			size = {0.15, 0.6},
			gravity = {0,0,0},
			airResistance = 5,
			rotationSpeed = 1,
			blendMode = "Additive",
		},

		-- glow
		{
			spawnBurst = true,
			emissionRate = 1,
			emissionTime = 0,
			maxParticles = 1,
			boxMin = {0,0,0.0},
			boxMax = {0,0,0.0},
			sprayAngle = {0,30},
			velocity = {0,0},
			texture = "assets/textures/particles/glow.tga",
			lifetime = {1000000, 1000000},
			colorAnimation = true,
			color0 = {1,0.5,0.5},
			color1 = {0.5,1.,0.5},
			color2 = {0.5,0.5,0.1},
			color3 = {1,1,0.5},
			opacity = 0.1,
			fadeIn = 0.1,
			fadeOut = 0.1,
			size = {0.4, 0.6},
			gravity = {0,0,0},
			airResistance = 1,
			rotationSpeed = 2,
			blendMode = "Additive",
			objectSpace = true,
		}
	}
}

defineParticleSystem{
	name = "zo_spell_hit",
	emitters = {
		-- sparks
		{
			emissionRate = 80,
			emissionTime = 0.3,
			maxParticles = 30,
			boxMin = {-0.5, -0.5, -0.5},
			boxMax = { 0.5,  0.5,  0.5},
			sprayAngle = {0,360},
			velocity = {0,0},
			objectSpace = false,
			texture = "mod_assets/exsp/spells/exsp_zo_spell.tga",
			frameRate = 4,
			frameSize = 256,
			frameCount = 4,
			lifetime = {0.2,0.5},
			color0 = {2.5,2.5,2.5},
			opacity = 1,
			fadeIn = 0.1,
			fadeOut = 0.3,
			size = {0.3, 1.4},
			gravity = {0,0,0},
			airResistance = 1,
			rotationSpeed = 0,
			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 = {1, 1, 1},
			opacity = 0.5,
			fadeIn = 0.01,
			fadeOut = 0.5,
			size = {1, 1},
			gravity = {0,0,0},
			airResistance = 1,
			rotationSpeed = 2,
			blendMode = "Additive",
		}
	}
}

-- ****** Define Object and noLaunch version ******

defineObject{
	name = "zo_spell",
	class = "ProjectileSpell",
	particleSystem = "zo_spell",
	hitParticleEffect = "zo_spell_hit",
	lightColor = vec(0.6, 0.6, 0.6),
	lightBrightness = 10,
	lightRange = 4,
	lightHitBrightness = 12,
	lightHitRange = 7,
	castShadow = true,
	launchSound = "silence",
	projectileSound = "blob",
	hitSound = "blob_hit",
	projectileSpeed = 10,
	attackPower = 1,
	damageType = "shock",
	--cameraShake = true,
	tags = { "spell" },
}

-- ****** Define spell & spell scroll ******

defineSpell{
	name = "zo_spell",
	uiName = "Zo Spell",
	skill = "spellcraft",
	level = 10,
	runes = "H",
	manaCost = 20,
	description = "A bolt of magical negative energy which can open a door from a distance.",
	onCast = function(caster,x,y,direction,skill)
		exsp:spellCast("zo_spell", caster)
	end
}

defineObject{
		name = "scroll_zo_spell",
		class = "Item",
		uiName = "Scroll of Zo Spell",
		model = "assets/models/items/scroll_spell.fbx",
		gfxIndex = 113,
		scroll = true,
		spell = "zo_spell",
		weight = 0.3,
		description = [[
			A bolt of magical negative energy which can open a door from a distance.
			Note that certain doors are magically shielded and will resist the spell.
			]]	
	}
	
-- ****** Define script functions ******


fw_addModule("exsp_zo_spell",[[
	function autoexec()
		exsp:defineSpell("zo_spell",{
			-- Basic information
			spawnObject = "zo_spell",
			projectileSpeed = 10,
			damageType = "none",
			
			-- Particle Systems
			particleSystem = "zo_spell",
			hitParticleEffect = "zo_spell_hit",

			-- Light properties
			lightColor = {0.6, 0.6, 0.6},
			lightBrightness = 10,
			lightRange = 4,
			lightHitBrightness = 15,
			lightHitRange = 7,
			castShadow = true,
			
			-- Sounds
			launchSound = "generic_spell",
			projectileSound = "blob",
			hitSound = "blob_hit",

			-- Hooks
			onHit = function(self, level, x, y, hitType, subType, entity)
				if hitType == "door" and grimq.strends(entity.id, "zo") then
					entity:open()
				end
			end
			}
		)
	end
]])
Gunsrequiem
Posts: 4
Joined: Thu Jan 17, 2013 12:11 am

Re: Scripting "Force Open" spell--intended to open doors

Post by Gunsrequiem »

Wow!

This is some seriously excellent work! Thank you so much, mate.
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: Scripting "Force Open" spell--intended to open doors

Post by Diarmuid »

Oh, btw, I just uploaded an almost final version of exsp 1.4 at the link above. I've tested it a lot this time, but there might always be a little bug here and there, if there's anything wrong, call out.

I've uploaded it right away so you can take the file if you wish, but I'll still finish the wiki site I'm making for it with full instructions and documentation, and then make an official announcement in the EXSP framework thread with a detailed changelog and such.
Post Reply