Page 1 of 2

question based on monster.lua

Posted: Fri Jan 04, 2013 8:57 pm
by hyteria
hello ,

it is possible to use a funcion who call a script in game on a defineobjectmonster ?

well i work on a mob who can summon another monster

or maybee it s more easy to create another spell like summoning (based on spawn) and add this spell on rangedattack?

thx

Re: question based on monster.lua

Posted: Fri Jan 04, 2013 10:08 pm
by Isaac
[AFAIK] You would have to define the summon-able monster during initialization, but could use a hook to call the spawn function; and spawn an instance of the defined monster.

Re: question based on monster.lua

Posted: Fri Jan 04, 2013 10:11 pm
by HaunterV
Well to me, it sounds like your spell would need to call on the summoner-monster position (i will now refer to as SM for convenience sake), SM facing, and check for a vacant tile to place the monster being summoned. After all that, the only way I can think of it working is with an invisible teleporter teleporting the summoned monster from a square with a spawner that spawns the desired monster to the SM target tile.

I'm sure Grimwold or someone could put it better.

Re: question based on monster.lua

Posted: Fri Jan 04, 2013 10:18 pm
by hyteria
oh thx for replying this help me )

Re: question based on monster.lua

Posted: Wed Mar 06, 2013 8:26 pm
by akroma222
Grimwold's script using teleport probes could indeed help here.. I was actually thinking of doing something very similar (SM)...
I have used a similar script to spawn teleporters in 'Valid' positions....

This script comes from Grimwolds Push Monster spell -
SpoilerShow
function monsterThere(level,eggs,why)
for i in entitiesAt(level,eggs,why) do
if isInTable(allMonstersPush,i.name)
then
return true
end
end
return false
end

function pushDestroy()
push_teleport:destroy()
push_timer:destroy()
end

function isValidTarget(L,X,Y)
spawn("spawner", L, X, Y, 0, "probe"):setSpawnedEntity("teleport_probe"):activate()
for j in entitiesAt(L,X,Y) do
if j.name == "teleport_probe" then
probe:destroy()
j:destroy()
return true
end
end
probe:destroy()
return false
end

function pushbackSpell(caster,x,y,dir,skill)
local dx,dy = getForward(dir)
if monsterThere(party.level,x+dx,y+dy) then
-- hudPrint("Monster!")
if isValidTarget(party.level,x+2*dx,y+2*dy) then
-- hudPrint("PUSH!!!!")
spawn("fx", party.level, x+dx, y+dy, dir, "push_smoke")
:setParticleSystem("push_spell")
:translate(0, 0.5, 0)
playSoundAt("fireball_launch",party.level,x+dx,y+dy)
spawn("teleporter", party.level, x+dx,y+dy,dir, "push_teleport")
:setTeleportTarget(x+2*dx,y+2*dy, dir)
:setTriggeredByParty(false)
:setTriggeredByMonster(true)
:setTriggeredByItem(false)
:setChangeFacing(true)
:setInvisible(true)
:setSilent(true)
:setHideLight(true)
:setScreenFlash(false)
spawn("timer",party.level,x,y,dir,"push_timer")
:setTimerInterval(0.1)
:addConnector("activate", "grimwold_spell_script", "pushDestroy")
:activate()
else
hudPrint("The spell fails because there is something in the way.")
end
else
hudPrint("The spell fails because there is no monster to push")
end
end
And this is an adaption of it for my mod...
SpoilerShow
function cavesAccess(caster,x,y,dir,skill)
local dx,dy = getForward(party.facing)
if findEntity("createdWall") ~= nil and findEntity("createdWall"):isOpen() then
if isValidCaveTarget(party.level,party.x+dx,party.y+dy,party.facing) then
spawn("fx", party.level, party.x+dx, party.y+dy, party.facing, "poisonous")
:setParticleSystem("poisonous")
:translate(0, 0.5, 0)
spawn("teleporter_green_01", party.level, party.x+dx, party.y+dy, party.facing, "teleporter_green_02")
:setTeleportTarget(12, 5, 3, 17)
:setTriggeredByParty(true)
:setTriggeredByMonster(false)
:setTriggeredByItem(true)
:setChangeFacing(true)
:setInvisible(false)
:setSilent(true)
:setHideLight(false)
:setScreenFlash(false)
:activate()
spawn("pressure_plate_hidden", party.level, party.x+dx, party.y+dy, party.facing, "teleporter_green_02_flash")
:setTriggeredByParty(true)
:setTriggeredByMonster(false)
:setTriggeredByItem(false)
:setSilent(true)
:activateOnce(false)
:addConnector("deactivate","colouredTeleportScript","FlashGreen")
else
hudPrint("The entry point fails because there is something in the way.")
end
findEntity("cavestimer"):destroy()
end

end



function isValidCaveTarget(L,X,Y)
spawn("spawner", L, X, Y, 0, "probe"):setSpawnedEntity("teleport_probe"):activate()
for j in entitiesAt(L,X,Y) do
if j.name == "teleport_probe" then
probe:destroy()
j:destroy()
return true
end
end
probe:destroy()
return false
end
I guess the important part here to start with would be
SpoilerShow
if isValidCaveTarget(party.level,party.x+dx,party.y+dy,party.facing) then
spawn("fx", party.level, party.x+dx, party.y+dy, party.facing, "poisonous")
...swapping 'monster' in for 'party' of course....
I will prolly have a red hot go at this soon, I will get back to you if/when I come up with a solution :D

Re: question based on monster.lua

Posted: Wed Mar 06, 2013 9:13 pm
by Ryeath_Greystalk
What is going to trigger the first monster to summon the next?

I'm not good at scripting yet so I use a 'cheater' method in one of my scripted fights. When the monsters reaches a certain amount of health he teleports to another room and more monsters spawn in which you have to defeat before you can enter the next room and continue the battle. How I do it..

I have a one square room with a deactivated teleporter in it. I place the monster in there at start up so I can give it my own unique ID. (I haven't had any success spawning monsters with a unique ID yet, thus I cheat :) ) When it's time for the main boss to be summoned I use a script to activate the portal which puts the monster in the room with the party. I make sure there is no way the party can be blocking the teleporter point of exit.

Then at the same time I start a looping timer that checks for the monster health every 5 seconds and when it drops below a certain threshold I use the monster:setLocation(x.y.level) (or whatever, I have to look it up again) to 'teleport' the monster to the next room.

Then I use that same script to activate custom monsters that have an onDie hook to decrement a counter so when all the mobs are dead it opens the door to the next room.

Rinse & repeat until main monster is dead.

I think a method like this could be converted to something usable for you if you can't figure out a more professional way to do it.

Good luck.

Re: question based on monster.lua

Posted: Thu Mar 07, 2013 2:25 am
by Marble Mouth
Hi hyteria. While it would be possible to add your summoning code to the monster's onRangedAttack hook, this will only get triggered when the monster decides to use its ranged attack, based on its brain. This may or may not be appropriate for the effect you're trying to achieve. You could also consider any other monster hook; I think either onDamage or onDealDamage might make sense. A "vampiric" monster for example might summon an ally every time it deals damage, and set that new ally's health equal to the damage dealt. I believe someone made slimes that split when they are damaged. You could activate a timer when you detect that the party is near the monster (hidden pressure plate or the monster's onAttack hook?) and have the timer activate the spawn. Of course, this method will be more complicated if there's going to be more than one of these summoner monsters in your dungeon, since you'll need some scheme to track which one(s) should be summoning currently. I think that no matter what scheme you use to trigger the spawn/summon, you will have to consider if the quantity of spawned monsters can become large, and if you're ok with that possibility.

Hi Akroma222. I think that the newly standardized function isWall(level, x, y) obviates the need for teleport probes, although the probes were a great innovation at the time.

Hi Ryeath_Greystalk. I assume that your boss monster has lots of health, so it should not be possible to bring it below the threshold and kill it in the same 5s, but what if? The easiest solution might be to give the boss an onDie hook so that it can't possibly die unless it confirms that it has already escaped to the next room. I think an even better solution would involve replacing your 5s timer with an onDamage hook:
SpoilerShow
monsters.lua:

Code: Select all

cloneObject{
--your boss monster's other properties here
onDie = function( monster )
   return bossScript.onDie( monster )
end,
onDamage = function( monster , damageAmount , damageType )
   return bossScript.onDamage( monster , damageAmount , damageType )
end,
}
script_entity named bossScript:

Code: Select all

onDie = function( monster )
   if not alreadyEscaped then
      return false
   end
end

threshold = 9001 --or whatever number

onDamage = function( monster , damageAmount , damageType )
   if ( not alreadyEscaped ) and ( ( monster:getHealth() - damageAmount ) < threshold ) then
      --do your escape stuff here
      alreadyEscaped = true
      if ( damageAmount > monster:getHealth() ) then
         --prevent the boss from being killed by a massive attack before it has escaped
         Monster:setHealth(1)
         return false
      end
   end
end
I wasn't certain after reading through your post: can your boss escape more than once to other rooms? If so, you'll probably want alreadyEscaped to be a number instead of a boolean (increment on each escape instead of set to true), and threshold will be a table (an array of thresholds really) instead of a number. The script will look a bit different, but the idea will be the same.

Re: question based on monster.lua

Posted: Thu Mar 07, 2013 3:01 am
by Ryeath_Greystalk
Marble Mouth,

Thanks for the advice.

My first thought was to use an onDamage hook, but I couldn't figure out how it worked as my scripting knowledge is rudimentary at best. Mainly what confused me is how to address the damage type variable, not sure what to put there. That's why I resorted to a cheater method. I have not got the entire fight scripted out yet, but it will take place over several rooms with teleports at 75%, 50% and 25%.

I do appreciate the scripting you posted and as soon as I get a chance I will sit down and see if I can figure out exactly what it's doing and if I can implement it.

(didn't mean to thread jack hysteria's post)

Re: question based on monster.lua

Posted: Thu Mar 07, 2013 4:10 am
by akroma222
Ah huh!! Thanks for that, somehow the isWall() has evaded me till now :) Obviated indeed
In fact, isWall() has just made my day
Those are some pretty good solutions, nice work!

Re: question based on monster.lua

Posted: Thu Mar 07, 2013 7:40 pm
by Ryeath_Greystalk
[quote="Marble Mouth"]
SpoilerShow
monsters.lua:

Code: Select all

cloneObject{
--your boss monster's other properties here
onDie = function( monster )
   return bossScript.onDie( monster )
end,
onDamage = function( monster , damageAmount , damageType )
   return bossScript.onDamage( monster , damageAmount , damageType )
end,
}
script_entity named bossScript:

Code: Select all

onDie = function( monster )
   if not alreadyEscaped then
      return false
   end
end

threshold = 9001 --or whatever number

onDamage = function( monster , damageAmount , damageType )
   if ( not alreadyEscaped ) and ( ( monster:getHealth() - damageAmount ) < threshold ) then
      --do your escape stuff here
      alreadyEscaped = true
      if ( damageAmount > monster:getHealth() ) then
         --prevent the boss from being killed by a massive attack before it has escaped
         Monster:setHealth(1)
         return false
      end
   end
end
Marble Mouth,

I had a couple questions on your script if you don't mind. (or I could move to a new thread or PM's to not clog up hysterias thread.)

I see you have onDie and onDamage in both the monsters.lua and bossScript. Are they calling the same functions or are they separate? For example could I use
monsters.lua
onDie = function( monster )
return bossScript.isItDeadYet( monster )
end,

with bossScript
function isItDeadYet(monster)

Another unclear this is alreadyEscaped variable. I don't see it assigned to anything until after the monster has escaped where you give it alreadyEscaped = true.
Wouldn't that bring up an error for a nil value? I tend to think very linear. So I would think it would happen like this, I hit monster, monster takes damage, call bossScript.onDamage, function tries to compare not alreadyEscaped..lua say "whoa, what is this alreadyEscaped thing I haven't seen that yet, guess I will give it a nil value."

Thanks in advance.