To give you a more complete solution, although - only briefly tested. There are 3 cases to consider...
1. With a ranged weapon (silver throwing dagger or magic arrow) it's easy. You just have to override the monster's 'onProjectileHit' method so that you destroy the monster when hit by the specific weapon. Note that this solution doesn't give the shooter XP for the kill. You could either just give each character 1,000 XP for killing this boss or you could possibly do something funny, like unset a flag so that 'onDamage' no longer returns false. Then give the monster 0 protection, 0 evade and 1 hit point (so that hit also definitely kills the creature).
The following example creates a snail clone (called 'magic_snail') that can only be killed by a special arrow. Everything else does no damage.
Code: Select all
cloneObject{
name = "magic_snail",
baseObject = "snail",
protection = 1000,
evasion = -100,
onProjectileHit = function(monster, projectile, damage, damageType)
if ( projectile.name == "my_magic_arrow" ) then
spawn("fx", monster.level, monster.x, monster.y, monster.facing):setParticleSystem("shockburst"):translate(0,1,0);
spawn("fx", monster.level, monster.x, monster.y, monster.facing):setParticleSystem("hit_blood"):translate(0,1,0);
monster:destroy();
end
end,
onDamage = function(monster, damage, damageType)
return false;
end
}
cloneObject{
name = "my_magic_arrow",
baseObject = "arrow",
uiName = "Magic Arrow"
}
2. You have a wand or weapon that casts a spell on the square in front of the party which can kill the creature. This is also pretty straightforward - you just have to create a custom spell, and have that spell detect the specific creature and destroy it. Same issue with XP, but apart from that - pretty easy.
This example extends the above example by making it so that a specific spell can also kill the snail. In this case, the spell must be cast by the 'Magic Snail Killer' rod, which is a clone of the lightning rod.
Code: Select all
-- SAME SNAIL FROM ABOVE
cloneObject{
name = "my_magic_spell_rod",
baseObject = "lightning_rod",
uiName = "Magic Snail Killer",
attackMethod = "castWandSpell",
spell = "kill_magic_snail_spell",
charges = 100
}
defineSpell{
name = "kill_magic_snail_spell",
uiName = "Murder Magic Snail",
skill = "air_magic",
level = 10,
runes = nil,
manaCost = 0,
onCast = function(caster, x, y, facing, skill)
local dx, dy = getForward(facing);
local spell_x, spell_y = x+dx, y+dy;
local level = party.level;
if ( isWall(level, spell_x, spell_y) ) then
return;
end
spawn("fx", level, spell_x, spell_y, facing):setParticleSystem("shockburst"):translate(0,1,0);
for e in entitiesAt(level, spell_x, spell_y) do
if ( e.name == "magic_snail" ) then
spawn("fx", level, spell_x, spell_y, facing):setParticleSystem("hit_blood"):translate(0,1,0);
e:destroy();
end
end
end
}
3. For melee weapons, I don't think there is an easy way to track the weapon used in onDamage. For this, you will have to create a script_entitiy and store some data. I've written a fairly fool-proof mechanism I think. Whenever you attack, store the weapon used and the play_time (frame time). If an onDamage call is made in the same frame, I assume it's the same attack. You have to do this to prevent the player from firing an arrow, swinging a sword and then having the arrow hit and kill the creature - just tracking the weapon would then lead it to think the sword hit it. By tracking the time, we ensure this only works for melee weapons and ignores ranged weapons.
This is a two step solution...
STEP 1. You will need to add the following script_entity to your dungeon with the name 'attack_tracker'. This is a script that will be called from both the party hook and the monster to ensure that attacks are tracked.
Code: Select all
last_attack_weapon = nil;
last_attack_time = nil;
function onAttack(champion, weapon)
local weapon_name = "";
if ( weapon == nil ) then
weapon_name = "Unarmed"
else
weapon_name = weapon.name;
end
last_attack_weapon = weapon_name;
last_attack_time = getStatistic("play_time");
end
function getAttackingWeapon()
if ( last_attack_time == getStatistic("play_time") ) then
return last_attack_weapon;
end
return nil;
end
STEP 2. Update the snail to the following and add the 'cloneObject' party hook for the onAttack hook. Note that if you already have an onAttack hook, you will need to merge the code otherwise one will override the other.
Code: Select all
cloneObject{
name = "magic_snail",
baseObject = "snail",
protection = 1000,
evasion = -100,
onProjectileHit = function(monster, projectile, damage, damageType)
if ( projectile.name == "my_magic_arrow" ) then
spawn("fx", monster.level, monster.x, monster.y, monster.facing):setParticleSystem("shockburst"):translate(0,1,0);
spawn("fx", monster.level, monster.x, monster.y, monster.facing):setParticleSystem("hit_blood"):translate(0,1,0);
monster:destroy();
end
end,
onDamage = function(monster, damage, damageType, other)
local tracker = findEntity("attack_tracker");
if ( tracker ~= nil and tracker.getAttackingWeapon() == "knife" ) then
spawn("fx", monster.level, monster.x, monster.y, monster.facing):setParticleSystem("shockburst"):translate(0,1,0);
spawn("fx", monster.level, monster.x, monster.y, monster.facing):setParticleSystem("hit_blood"):translate(0,1,0);
monster:destroy();
end
return false;
end
}
cloneObject{
name = "party",
baseObject = "party",
onAttack = function(champion, weapon)
local tracker = findEntity("attack_tracker");
if ( tracker ~= nil ) then
tracker.onAttack(champion, weapon);
end
end
}
At the end of this you should have an invulnerable snail - only 3 things can kill it... A knife in melee, a magic arrow and a spell rod which casts a specific spell.
If you want to see it in action before trawling through the above code - I've created an example dungeon with a room of magic snails. They can only be killed with the knife, the magic arrows and the lightning rod. Everything else should do zero damage. Feel free to pick apart the code from there instead if you would prefer. Enjoy!
http://www.johnwordsworth.com/downloads ... llTest.zip