Scripting: Monster only gets demaged by one special weappon

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
User avatar
THOM
Posts: 1274
Joined: Wed Nov 20, 2013 11:35 pm
Location: Germany - Cologne
Contact:

Scripting: Monster only gets demaged by one special weappon

Post by THOM »

What I try to do is to have a costum monster that can only get demaged by one special weappon.

I found this scripting-idea:
viewtopic.php?f=14&t=4335&hilit=monster+kill

But thats a different idea: a monster is killed immediatly with that special weappon but is also hurtable otherwise.

My monster must not be killed immediatly, but has to get demage by only one weappon.

What I did already is to set my monster to

Code: Select all

health = 20000,
immunities = { "poison", "assassination", "backstab", "fire", "cold", "shock"  },
evasion = 1000,
Just a first try but that must set it to nearly immortality (for fights with other weappons). But I don't know how to implement a weappon, that is able now to do damage to this monster... ?? :?: :?
THOM formaly known as tschrage
_______________________________________________
My MOD (LoG1): Castle Ringfort Thread
My MOD (LoG2): Journey To Justice Thread | Download
User avatar
DesperateGames
Posts: 90
Joined: Sun Oct 06, 2013 1:54 pm

Re: Scripting: Monster only gets demaged by one special weap

Post by DesperateGames »

I had a similar problem in my dungeon, and i added the following to the monster definition:

Code: Select all

onDamage=function(monster,amount,type)
		if type=="poison" then 
			return true 
		else 
			return false
		end
	end,
A monster that has this OnDamage hook will only be wounded by poison damage. (Which my magic weapon of course does deal, what a coincidence ;-) ) The downside is that the monster will absolutely ignore all other damage, it is like you are not even hitting at all. I remember that I tried several things to reduce the amount of all other incoming damage, but I don't know what the problem / issue was, all I can remember is that it did not work unless I would block all other damage. :?
User avatar
THOM
Posts: 1274
Joined: Wed Nov 20, 2013 11:35 pm
Location: Germany - Cologne
Contact:

Re: Scripting: Monster only gets demaged by one special weap

Post by THOM »

Ah, DesperateGames, once again it's you, who helps me. :-)

But your solution suggests "poison", which would mean, that my monster would get demage from all poision-attacks (eg. poison-cloud).

But I would like to have a monster that takes absolutly no demage from any kind of attack - only from that special weappon.

I don't mind, how I could make my monster immune to attacks - my problem is: how to get one weappon, that does demage...
THOM formaly known as tschrage
_______________________________________________
My MOD (LoG1): Castle Ringfort Thread
My MOD (LoG2): Journey To Justice Thread | Download
User avatar
AdrTru
Posts: 223
Joined: Sat Jan 19, 2013 10:10 pm
Location: Trutnov, Czech Republic

Re: Scripting: Monster only gets demaged by one special weap

Post by AdrTru »

I think that you must create party hook for onAttack and weapon set to some global variable ( maybe with timestamp ).
Next in monster hook onDamage you may compare this used weapon for make/dont make damage. ( timestamp will be same for same attack )
My LOG2 projects: virtual money, Forge recipes, liquid potions and
MultiAlcoveManager, Toolbox, Graphic text,
User avatar
maneus
Posts: 246
Joined: Mon Jun 17, 2013 10:42 pm
Location: Switzerland

Re: Scripting: Monster only gets demaged by one special weap

Post by maneus »

Maybe this could work:

In your monsters.lua make a onDamage script like this to your monster:

Code: Select all

   	onDamage = function (self, dmg, dmgType)
     	 return damage.checkDamage(self, dmg, dmgType)
	end,
Then make a script in your dungeon named "damage".

Put the following into the script:

Code: Select all

usedWeapon = ""

function checkDamage(self, dmg, dmgType)

   if usedWeapon == "name your weapon here" then
      usedWeapon = ""
      return true

   else

      usedWeapon = ""
      return false
		end
       end
end


function whatWeapon(self, weapon)

   if weapon then
      usedWeapon = weapon.name
   end
   return true

end
This works with destroyable objects. Maybe with monsters too?
User avatar
AdrTru
Posts: 223
Joined: Sat Jan 19, 2013 10:10 pm
Location: Trutnov, Czech Republic

Re: Scripting: Monster only gets demaged by one special weap

Post by AdrTru »

Yes, its applicating of my idea, But in your examle IMHO missing call to whatWeapon(self, weapon) from patry like this

Code: Select all

onAttack = function(self, weapon)
  damage.whatWeapon(self, weapon)
end
becouse without calling this function this usedWeapon will dont be setted.
My LOG2 projects: virtual money, Forge recipes, liquid potions and
MultiAlcoveManager, Toolbox, Graphic text,
User avatar
JohnWordsworth
Posts: 1397
Joined: Fri Sep 14, 2012 4:19 pm
Location: Devon, United Kingdom
Contact:

Re: Scripting: Monster only gets demaged by one special weap

Post by JohnWordsworth »

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
My Grimrock Projects Page with links to the Grimrock Model Toolkit, GrimFBX, Atlas Toolkit, QuickBar, NoteBook and the Oriental Weapons Pack.
User avatar
AdrTru
Posts: 223
Joined: Sat Jan 19, 2013 10:10 pm
Location: Trutnov, Czech Republic

Re: Scripting: Monster only gets demaged by one special weap

Post by AdrTru »

Wow.
Thank you for very compex and usefull solution.
My LOG2 projects: virtual money, Forge recipes, liquid potions and
MultiAlcoveManager, Toolbox, Graphic text,
User avatar
maneus
Posts: 246
Joined: Mon Jun 17, 2013 10:42 pm
Location: Switzerland

Re: Scripting: Monster only gets demaged by one special weap

Post by maneus »

AdrTru wrote:Yes, its applicating of my idea, But in your examle IMHO missing call to whatWeapon(self, weapon) from patry like this

Code: Select all

onAttack = function(self, weapon)
  damage.whatWeapon(self, weapon)
end
becouse without calling this function this usedWeapon will dont be setted.
Oh right, I forget this:

I´ve put in objects.lua the following:

Code: Select all

cloneObject{
   name = "party",
   baseObject = "party",
   onAttack = function (self, weapon)
      return damage.whatWeapon(self, weapon)
   end,
}
User avatar
THOM
Posts: 1274
Joined: Wed Nov 20, 2013 11:35 pm
Location: Germany - Cologne
Contact:

Re: Scripting: Monster only gets demaged by one special weap

Post by THOM »

Oh, well - seems to be good. The only thing I want to change in JohnWordsworth solution is, that I don't want to have the monster be killed immediatly, I want to get it damaged.

So instead of monster:destroy(); I would write something like

Code: Select all

 monster:setHealth(-100)

Is this possible?
THOM formaly known as tschrage
_______________________________________________
My MOD (LoG1): Castle Ringfort Thread
My MOD (LoG2): Journey To Justice Thread | Download
Post Reply