Boss fight help

Ask for help about creating mods and scripts for Grimrock 2 or share your tips, scripts, tools and assets with other modders here. Warning: forum contains spoilers!
minmay
Posts: 2789
Joined: Mon Sep 23, 2013 2:24 am

Re: Boss fight help

Post by minmay »

Azel wrote:Even the Grimrock scripting reference has contradictions that only diminish after "reading between the lines" (eg, "CrystalComponent:setCooldown(number) leads us to a successful, my_crystal.crystal:setCooldown(60)" ... whereas "MonsterAttackComponent:getAttackPower() leads to a failure if you try, my_monster.monsterattack:getAttackPower()"). Granted, once you find out what went wrong you realize it was your fault for not understanding the Scripting Reference better, but at the end of the day it still feels quite sloppy, imo.
Man, I'm no fan of Lua either, but I think it's reasonable to expect programmers to know that a class name and a table key aren't the same thing. It's not the Grimrock scripting reference's job to teach compsci 101, or introduce you to Lua, it's just there to list what's available in Grimrock specifically.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Azel
Posts: 808
Joined: Thu Nov 06, 2014 10:40 pm

Re: Boss fight help

Post by Azel »

minmay wrote:Man, I'm no fan of Lua either, but I think it's reasonable to expect programmers to know that a class name and a table key aren't the same thing. It's not the Grimrock scripting reference's job to teach compsci 101, or introduce you to Lua, it's just there to list what's available in Grimrock specifically.
I think it's the other way around: the scripting reference and asset pack could use some CompSci 101. The idea of subclasses, for example, requires Inheritance, which is nowhere to be found in the Asset definitions (instead, multiple classes are shoved in to a single component).

Furthermore, the scripting reference lists out Components and their functions/behaviors, and it explicitly states, "By default the name of a component is the class name in lower case." There is nowhere on the Scripting Reference that indicates which of their Component syntax items refers to a Table instead of a Class.

Pointing out that in some cases the Scripting Reference is referring to a table key is fine, but assuming that someone doesn't know the difference is a logical leap. Tables in LUA are nothing more than array containers for key/value pairs; and incredibly basic compared to other languages (https://msdn.microsoft.com/en-us/librar ... 10%29.aspx).

I agree that it's not the scripting references job to teach anything, but it certainly should properly reference a Method that is called at the Class lvl vs a sub-type. Other script references work on their own just fine, such as:
https://dev.twitter.com/streaming/overv ... m_messages
https://developers.google.com/+/web/api/rest/latest/

In the example I gave about MonsterAttack, the scripting reference calls it a Component (which they describe as having its class name in lowercase), but it's not until you delve in to the asset pack that you find the proper item to implement the method call.

Anyway, I did agree that some fault lies on the reader (ie, I own which failures are my own). But, I also maintain an awareness that these failures are rarely present in scripting references that are more thorough and accurate.
DrKojak
Posts: 23
Joined: Fri Oct 24, 2014 11:19 am

Re: Boss fight help

Post by DrKojak »

I always just have the monster in a deactivated teleporter in some far corner of the map, when the boss starts, activate the teleporter and set the custom destination.
if the monster is in a 1x1 tile, he wont turn or move, so you can keep the monsters facing too!, you can set the teleporter destination higher that the floor, so he drops down and gives you a surprise if you wish.
User avatar
Isaac
Posts: 3188
Joined: Fri Mar 02, 2012 10:02 pm

Re: Boss fight help

Post by Isaac »

DrKojak wrote:I always just have the monster in a deactivated teleporter in some far corner of the map, when the boss starts, activate the teleporter and set the custom destination.
if the monster is in a 1x1 tile, he wont turn or move, so you can keep the monsters facing too!, you can set the teleporter destination higher that the floor, so he drops down and gives you a surprise if you wish.
Good for Spiders. :twisted:
Azel
Posts: 808
Joined: Thu Nov 06, 2014 10:40 pm

Re: Boss fight help

Post by Azel »

DrKojak wrote:I always just have the monster in a deactivated teleporter in some far corner of the map, when the boss starts, activate the teleporter and set the custom destination.
if the monster is in a 1x1 tile, he wont turn or move, so you can keep the monsters facing too!, you can set the teleporter destination higher that the floor, so he drops down and gives you a surprise if you wish.
Definitely an easier solution. I use this a lot. When I created the Usurper boss battle, I wrote the auto-spawn script because the Fire Boss needs to come back to life if the player kills him without meeting certain conditions. So in this case, script is needed to continuously spawn the Boss and dynamically add him to the Boss Battle object every time he dies. However, once the player meets the proper conditions and kills the Boss, he is allowed to stay dead, and I do use the Teleporter/Placeholder trick to bring in the final enemy for the boss battle.

Although I did not know that the monster doesn't turn if in a 1x1 square! I always configure the "spin" option on teleporters to make sure things face the direction I want :geek:
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Boss fight help

Post by akroma222 »

Another example for you....
Paste this into a script entity called 'bossScripts'
Activate the function bossstart() via pressure plate or something...
SpoilerShow

Code: Select all

viperBossDefeated = false

function checkForThings(thing,xMin,xMax,yMin,yMax)
	for x = xMin,xMax do
    	for y = yMin,yMax do
        	for entity in self.go.map:entitiesAt(x,y) do
            	if entity.name == thing then
                	return true
                end
            end
        end
    end
    return false
end
	
function viperBossFinish()
	local b = findEntity("vinesBossFight")
	local c = findEntity("vinesBossCounter")
	
	if viperBossDefeated == false 
	and not (checkForThings("viperRootBoss_1",1,31,1,31) 
	or checkForThings("viperRootBoss_2",1,31,1,31) 
	or checkForThings("viperRootBoss_3",1,31,1,31)) then
    	viperBossDefeated = true
		if b ~= nil then
			b:destroyDelayed()
		end
		if c ~= nil then
			c:destroyDelayed()
		end 
		hudPrint("Boss fight finished")
	end
end

	function bossstart()
		
		if viperBossDefeated == true then
			hudPrint("You have already fought the boss")
       		return false
		end
		
		--if wanting to check within an area on self.level
		if viperBossDefeated == false then
			for n = 1,3 do
				if findEntity("viperRootBoss_"..n) ~= nil then
					local vleft = viperBossCounter.counter:getValue()
					local vName = vinesBossFight.bossfight:getBossName()
					if vleft > 1 then
						hudPrint("You are currently fighting the boss... there are still "..vleft.." "..vName.."s remaining.")
					elseif vleft == 1 then
						hudPrint("You are currently fighting the boss... there is only 1 "..vName.." remaining.")
					end
   					return false
				end
			end
       	end

		local b = findEntity("vinesBossFight")
		if b == nil and viperBossDefeated == false then
			local bScript = spawn("boss_fight", self.level,self.x,self.y,self.elevation,self.facing,"vinesBossFight")
			vinesBossFight.bossfight:setBossName("Viper Roots")
			vinesBossFight.bossfight:setAutoDeactivate(true)
			vinesBossFight.bossfight:setMusic("boss_fight_viper")
			vinesBossFight.bossfight:activate()
			
			local c = spawn("counter",self.level,self.x,self.y,self.elevation,self.facing,"viperBossCounter")
			c.counter:setValue(3)
			c.counter:addConnector("onActivate", "bossScripts", "viperBossFinish")
			
			for n = 1,3 do
				local v = spawn("viper_root",self.level,self.x,self.y,self.elevation,self.facing,"viperRootBoss_"..n)
				vinesBossFight.bossfight:addMonster(v.monster)
				v.monster:setMaxHealth(700)
				v.monster:addConnector("onDie", "viperBossCounter", "decrement")
			end
		end
	end
Keeps track of:
whether the fight has happened yet? (Happening currently, already over, or start!)
the number of monsters left in the fight
lets you check for remaining monsters within xMin,xMax,yMin,yMax area

Tested, let me know if any dramas
Akroma
Post Reply