Monster Detector

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!
GoldenShadowGS
Posts: 168
Joined: Thu Oct 30, 2014 1:56 am

Monster Detector

Post by GoldenShadowGS »

Update:
Latest version of the script

Code: Select all

defineSpell{
   name = "detect_monster",
   uiName = "Monster Detector",
   skill = "earth_magic",
   requirements = {"concentration", 1},
   gesture = 8,
   manaCost = 5,
   icon = 14,
   spellIcon = 13,
   description = "Reveals how many monster are nearby. Every point is Earth Magic increases your maximum detection range.",
   onCast = function(champion, x, y, direction, elevation, skillLevel)
      local monsterNames = {air_elemental = "an Air Elemental", crab = "a Crab", crowern = "a Crowern", dark_acolyte = "a Dark Acolyte", 
      eyctopus = "an Eyectopus", fire_elemental = "a Fire Elemental", fjeld_warg = "a Fjeld Warg", fjeld_warg1 = "a Fjeld Warg",
      fjeld_warg2 = "a Fjeld Warg", forest_ogre = "a Forest Ogre", giant_snake = "a giant Snake", goromorg = "a Goromorg", 
      herder = "a Herder", herder_big = "a big Herder", herder_small = "a small Herder", ice_guardian = "an Ice Guardian", 
      lindworm = "a Lindworm", lizard_ice = "an Ice Lizard", lizard_dark = "a Dark Lizard", lizard_fire= "a Fire Lizard", 
      lizard_green = "a Green Lizard", magma_golem = "a Magma Golem", medusa = "a Medusa", mimic = "a Mimic", 
      mosquito_swarm = "a Swarm of Mosquitos", mummy = "a Mummy", mummy1 = "a Mummy", mummy2 = "a Mummy", mummy3 = "a Mummy", 
      ogre = "a Cave Ogre", rat_swarm = "a Swarm of Rats", ratling = "a Ratling", ratling1 = "a Ratling", ratling2 = "a Ratling", 
      ratling_boss = "a Ratling Clan Chief", sand_warg = "a Sand Warg", scavenger = "a Scavenger", shrakk_torr = "a Shrakk Torr",
      skeleton_archer = "a Skeleton Archer", skeleton_commander = "a Skeleton Commander", skeleton_trooper = "a Skeleton Trooper", 
      skeleton_trooper1 = "a Skeleton Trooper", skeleton_trooper2 = "a Skeleton Trooper", skeleton_warrior = "a Skeleton Warrior",
      slime_green = "a Green Slime", slime_red = "a Red Slime", slime_blue = "a Blue Slime", slime_fire = "a Fire Slime", 
      slime_ice = "an Ice Slime", slime_dark = "a Dark Slime", slime_plasm = "a Plasma Slime",  slime_poison = "a Poison Slime",  
      slime_golden = "a Golden Slime", snail = "a Snail", snail_blue_green = "a Hardshell Snail", snail_green_brown = "a Deep Forest Snail",
      spider = "a Spider", spore_mushroom = "a Mushroom Sporer", summon_stone = "a Summon Stone", swamp_toad = "a Swamp Toad",
      tentacles = "a Pit Tentacle", trickster = "a Trickster", turtle = "a Turtle", turtle_diving = "a Turtle", twigroot = "a Twigroot",
      uggardian = "a Uggardian", undead = "a Zombie", viper_root = "a Viper Root", warden = "a Warden", wizard = "a Wizard", wyvern = "a Wyvern",
      xeloroid = "a Xeloroid", zarchton_diving = "a Zarchton", zarchton = "a Zarchton"}
      local monsterNamesplural = {air_elemental = "Air Elementals", crab = "Crabs", crowern = "Crowerns", dark_acolyte = "Dark Acolytes", 
      eyctopus = "Eyectopuses", fire_elemental = "Fire Elementals", fjeld_warg = "Fjeld Wargs", fjeld_warg1 = "Fjeld Wargs",
      fjeld_warg2 = "Fjeld Wargs", forest_ogre = "Forest Ogres", giant_snake = "giant Snakes", goromorg = "Goromorgs", 
      herder = "Herders", herder_big = "big Herders", herder_small = "small Herders", ice_guardian = "Ice Guardians", 
      lindworm = "Lindworms", lizard_ice = "Ice Lizards", lizard_dark = "Dark Lizards", lizard_fire= "Fire Lizards", 
      lizard_green = "Green Lizards", magma_golem = "Magma Golems", medusa = "Medusas", mimic = "Mimics", 
      mosquito_swarm = "Swarm of Mosquitos", mummy = "Mummies", mummy1 = "Mummies", mummy2 = "Mummies", mummy3 = "Mummies", 
      ogre = "Cave Ogres", rat_swarm = "Swarm of Rats", ratling = "Ratlings", ratling1 = "Ratlings", ratling2 = "Ratlings", 
      ratling_boss = "Ratling Clan Chiefs", sand_warg = "Sand Wargs", scavenger = "Scavengers", shrakk_torr = "Shrakk Torrs",
      skeleton_archer = "Skeleton Archers", skeleton_commander = "Skeleton Commanders", skeleton_trooper = "Skeleton Troopers", 
      skeleton_trooper1 = "Skeleton Troopers", skeleton_trooper2 = "Skeleton Troopers", skeleton_warrior = "Skeleton Warriors",
      slime_green = "Green Slimes", slime_red = "Red Slimes", slime_blue = "Blue Slimes", slime_fire = "Fire Slimes", 
      slime_ice = "Ice Slimes", slime_dark = "Dark Slimes", slime_plasm = "Plasma Slimes",  slime_poison = "Poison Slimes",  
      slime_golden = "Golden Slimes", snail = "Snails", snail_blue_green = "Hardshell Snails", snail_green_brown = "Deep Forest Snails",
      spider = "Spiders", spore_mushroom = "Mushroom Sporers", summon_stone = "Summon Stones", swamp_toad = "Swamp Toads",
      tentacles = "Pit Tentacles", trickster = "Tricksters", turtle = "Turtles", turtle_diving = "Turtles", twigroot = "Twigroots",
      uggardian = "Uggardians", undead = "Zombies", viper_root = "Viper Roots", warden = "Wardens", wizard = "Wizards", wyvern = "Wyverns",
      xeloroid = "Xeloroids", zarchton_diving = "Zarchtons", zarchton = "Zarchtons"}
      local monstertotal = 0
      --max range
      local count = 4 + skillLevel
      local monsterarray = {}
      local monsterdistance = {}
      local maxdist = 0
      --Fill the Monster Array
      for fx = x - count, x + count do
         for fy = y - count, y + count do
            for i in party.map:entitiesAt(fx,fy) do
               if i:getComponent("monster") then
                  monstertotal = monstertotal + 1
                  local xdist = (x - i.x) * 3
                  local ydist = (y - i.y) * 3
                  local zdist = (elevation - i.elevation) * 3
                  local dist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
                  if i.monster:getGroupSize() > 1 then
                     if monstertotal > 1 and i.x == monsterarray[monstertotal - 1].x and i.y == monsterarray[monstertotal - 1].y and i.elevation == monsterarray[monstertotal - 1].elevation then 
                        monstertotal = monstertotal - 1
                     else
                        monsterdistance[i] = dist
                     end
                  else
                     monsterdistance[i] = dist
                  end
                  if dist > maxdist then
                     maxdist = dist
                  end
                  monsterarray[monstertotal] = i
               end
            end
         end
      end
      local skillcount = 0
      playSound("generic_spell")
      for m = 0, maxdist do
         for k,v in pairs(monsterdistance) do
            if m == v and skillcount < skillLevel then
               local deltax = x - k.x
               local deltay = y - k.y
               local mdir = 0
               local height = ""
               if math.abs(deltax) <= math.abs(deltay) then
                  if deltay == 0 then
                     mdir = -1
                  elseif deltay > 0 then
                     mdir = (4 + direction) % 4
                  else
                     mdir = (6 + direction) % 4
                  end
               else
                  if deltax == 0 then
                     mdir = -1
                  elseif deltax > 0 then
                     mdir = (5 + direction) % 4
                  else
                     mdir = (7 + direction) % 4
                  end
               end
               if elevation == k.elevation then
                  height = ""
               elseif elevation < k.elevation then
                  height = ", above you"
               else
                  height = ", below you"
               end
               local fdir = ""
               if mdir == -1 then
                  fdir = height
               elseif mdir == 0 then
                  fdir = ""..height..", in front of the party"
               elseif mdir == 1 then
                  fdir = ""..height..", to the left of the party"
               elseif mdir == 2 then
                  fdir = ""..height..", behind the party"
               elseif mdir == 3 then
                  fdir = ""..height..", to the right of the party"
               end
               if skillLevel < 3 then
                  fdir = ""
               end
               skillcount = skillcount + 1
               if k.monster:getGroupSize() <= 1 then
                  hudPrint("There is "..monsterNames[k.name].." "..m.." meters away"..fdir..".")
               else
                  hudPrint("There is a group of "..k.monster:getGroupSize().." "..monsterNamesplural[k.name].." "..m.." meters away"..fdir..".")
               end
            end
         end
      end
   end,
}
--Original post

Here is a modified secret detector spell that lists the nearby monsters and how far away they are in the console.

Paste into spells.lua

Code: Select all

defineSpell{
	name = "detect_monster",
	uiName = "Monster Detector",
	skill = "earth_magic",
	requirements = {"concentration", 1},
	gesture = 8,
	manaCost = 5,
	icon = 14,
	spellIcon = 13,
	description = "Reveals how many monster are nearby. Every point is Earth Magic increases your maximum detection range.",
	onCast = function(champion, x, y, direction, elevation, skillLevel)
		local monstertotal = 0
		--max range
		local count = 4 + skillLevel
		local monsterarray = {}
		local monsterdistance = {}
		--Fill the Monster Array
		for fx = x - count, x + count do
			for fy = y - count, y + count do
				for i in party.map:entitiesAt(fx,fy) do
					if i:getComponent("monster") then
						monstertotal = monstertotal + 1
						local xdist = (x - i.x) * 3
						local ydist = (y - i.y) * 3
						local zdist = (elevation - i.elevation) * 3
						local dist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
						monsterdistance[monstertotal] = dist
						monsterarray[monstertotal] = i
					end
				end
			end
		end
		for i = 1, monstertotal do
			print(monsterarray[i].name, monsterdistance[i])
		end
	end,
}
Last edited by GoldenShadowGS on Fri Mar 06, 2015 9:29 pm, edited 1 time in total.
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Monster Detector

Post by akroma222 »

Hey GoldenShadowGS,

Thanks for posting this so quickly... I have come up with another working solution since we spoke...

This script will return information regarding -

distance (increased with skill level)
monster traits
monster conditions (burning etc...)
monster name
group and group size

It works fine except for if there is a monster group, the hudPrint reports a monster group for each monster in that group :o
I am not sure how manipulate the script so that it will recognize a bunch of monsters are in a group and only report this once in the hudPrint
SpoilerShow

Code: Select all

monsterNames = {air_elemental = "Air Elemental", crab = "Crab", crowern = "Crowern", dark_acolyte = "Dark Acolyte", 
				eyctopus = "Eyectopus", fire_elemental = "Fire Elemental", fjeld_warg = "Fjeld Warg", fjeld_warg1 = "Fjeld Warg",
				fjeld_warg2 = "Fjeld Warg", forest_ogre = "Forest Ogre", giant_snake = "Giant Snake", goromorg = "Goromorg", 
				herder = "Herder", herder_big = "Big Herder", herder_small = "Small Herder", ice_guardian = "Ice Guardian", 
				lindworm = "Lindworm", lizard_ice = "Ice Lizard", lizard_dark = "Dark Lizard", lizard_fire= "Fire Lizard", 
				lizard_green = "Green Lizard", magma_golem = "Magma Golem", medusa = "Medusa", mimic = "Mimic", 
				mosquito_swarm = "Swarm of Mosquitos", mummy = "Mummy", mummy1 = "Mummy", mummy2 = "Mummy", mummy3 = "Mummy", 
				ogre = "Cave Ogre", rat_swarm = "Swarm of Rats", ratling = "Ratling", ratling1 = "Ratling", ratling2 = "Ratling", 
				ratling_boss = "Ratling Clan Chief", sand_warg = "Sand Warg", scavenger = "Scavenger", shrakk_torr = "Shrakk Torr",
				skeleton_archer = "Skeleton Archer", skeleton_commander = "Skeleton Commander", skeleton_trooper = "Skeleton Trooper", 
				skeleton_trooper1 = "Skeleton Trooper", skeleton_trooper2 = "Skeleton Trooper", skeleton_warrior = "Skeleton Warrior",
				slime_green = "Green Slime", slime_red = "Red Slime", slime_blue = "Blue Slime", slime_fire = "Fire Slime", 
				slime_ice = "Ice Slime", slime_dark = "Dark Slime", slime_plasm = "Plasma Slime",  slime_poison = "Poison Slime",  
				slime_golden = "Golden Slime", snail = "Snail", snail_blue_green = "Hardshell Snail", snail_green_brown = "Deep Forest Snail",
				spider = "Spider", spore_mushroom = "Mushroom Sporer", summon_stone = "Summon Stone", swamp_toad = "Swamp Toad",
				tentacles = "Pit Tentacle", trickster = "Trickster", turtle = "Turtle", turtle_diving = "Turtle", twigroot = "Twigroot",
				uggardian = "Uggardian", undead = "Zombie", viper_root = "Viper Root", warden = "Warden", wizard = "Wizard", wyvern = "Wyvern",
				xeloroid = "Xeloroid", zarchton_diving = "Zarchton", zarchton = "Zarchton"}
				
monsterTraits = {animal = "animal", elemental = "elemental", flying = "flying", reptilian = "reptilian", wizard = "wizard",
				tentacle = "tentacle", slime = "slime", furry = "furry", ogre = "ogre", plant = "plant", crustacean = "crustacean", 
				aquatic = "aquatic", amphibious = "amphibious", undead = "undead", dragon = "dragon", construct = "construct", gorgon = "gorgon", 
				shapeshifter = "shapeshifter", insect = "insect", swarm = "swarm", vermin = "vermin", slug = "slug", arachnid = "arachnid",
				humanoid = "humanoid", horror = "horror"}
				
monsterNamesV = {air_elemental, eyctopus, ice_guardian, lizard_ice, slime_ice, uggardian}

monsterTraitsV = {"animal", "elemental", "ogre", "aquatic", "amphibious", "undead", "insect", "arachnid"}

CONDITIONS = {burning = false, sleeping = false, poisoned = false, frozen = false, stunned = false, entangled = false}

conditions = {}

traits = {}


function isInTable(table, element)
  for _,value in pairs(table) do
    if value == element then
      return true
    end
  end
  return false
end
--------------------------------------------------------------------------------------------------------------------------

		function detectmonster(champion, x, y, direction, elevation, skillLevel)

	 		local monsterfound = false
     		local count = 3 + skillLevel
        	local dist = -1
			local monsterCount = 0
			local group = false
			local groupSize = 0
			local name = ""
			local traitV = false
		
		 
			for fx = x - count, x + count do
        		for fy = y - count, y + count do
                	for i in party.map:entitiesAt(fx,fy) do
						
						if monsterCount > skillLevel then
							break
						end
					
                   		if i:getComponent("monster") then
						
							traits[i] = {}
							
							for k,v in pairs(monsterTraits) do 
								if i.monster:hasTrait(k) then
									table.insert(traits[i], v)
								end
							end
						
							for k,v in pairs(monsterNames) do 
								if i.name == k then
									name = v
									print(name) 
								end
							end
						
							if i.monster:getGroupSize() > 1 then
								group = true
								groupSize = i.monster:getGroupSize()
								print(group, groupSize)
							end
						
							conditions[i] = {}
						
							for k,v in pairs(CONDITIONS) do
								if i:getComponent(k) then
									CONDITIONS[k] = true
									if CONDITIONS[k] == true then
										table.insert(conditions[i], k)
										print(k,v)
										print(table.concat(conditions[i], ", "))
									end
								end
							end
                   
                        	local xdist = (x - i.x) * 3
                        	local ydist = (y - i.y) * 3
                        	local zdist = (elevation - i.elevation) * 3
                        	local sdist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
                         																		
                        	if sdist < dist or dist == -1 then
                       			dist = sdist
                        	end
                        	monsterfound = true
   
							if monsterfound == true then
								if champion:hasTrait("arcane_mastery") then
									if group == true then
										if conditions[i] ~= {} then
											hudPrint("There is a "..table.concat(conditions[i], ", ").." group of "..groupSize.." "..name.."s "..dist.." meters away.")
										else
											hudPrint("There is a group of "..groupSize.." "..name.."s "..dist.." meters away.")
										end
									else
										if conditions[i] ~= {} then
											hudPrint("There is a "..table.concat(conditions[i], ", ").." "..name.." "..dist.." meters away.")
										else
											hudPrint("There is a "..name.." "..dist.." meters away.")
										end
									end
								else
									if group == true then
										if conditions[i] ~= {} then
											hudPrint("There is a "..table.concat(conditions[i], ", ").." group of "..table.concat(traits[i], ", ").." monsters "..dist.." meters away.")
										else
											hudPrint("There is a group of "..table.concat(traits[i], ", ").."  monsters "..dist.." meters away.")
										end
									else
										if conditions[i] ~= {} then
											hudPrint("There is a "..table.concat(conditions[i], ", ").." "..table.concat(traits[i], ", ").." monster "..dist.." meters away.")
										else
											hudPrint("There is a "..table.concat(traits[i], ", ").." monster "..dist.." meters away.")
										end
									end
								end
       							playSound("generic_spell")
								monsterCount = monsterCount + 1
       						else
            					hudPrint("There are no monsters nearby.")
            					playSound("spell_fizzle")
			       			end
			   			end
					end
				end
 			end
		end
	
Hopefully there is a solution for this... thanks again for getting back to me so quickly :D

Akroma
GoldenShadowGS
Posts: 168
Joined: Thu Oct 30, 2014 1:56 am

Re: Monster Detector

Post by GoldenShadowGS »

The first thing that comes to mind is to compare if the monster group's x and y and elevation are equal to another monster, then throw away the duplicates.

You might be able to use something like this:

Code: Select all

defineSpell{
	name = "detect_monster",
	uiName = "Monster Detector",
	skill = "earth_magic",
	requirements = {"concentration", 1},
	gesture = 8,
	manaCost = 5,
	icon = 14,
	spellIcon = 13,
	description = "Reveals how many monster are nearby. Every point is Earth Magic increases your maximum detection range.",
	onCast = function(champion, x, y, direction, elevation, skillLevel)
		local monstertotal = 0
		--max range
		local count = 4 + skillLevel
		local monsterarray = {}
		local monsterdistance = {}
		--Fill the Monster Array
		for fx = x - count, x + count do
			for fy = y - count, y + count do
				for i in party.map:entitiesAt(fx,fy) do
					if i:getComponent("monster") then
						monstertotal = monstertotal + 1
						local xdist = (x - i.x) * 3
						local ydist = (y - i.y) * 3
						local zdist = (elevation - i.elevation) * 3
						local dist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
						if i.monster:getGroupSize() > 1 then
							if monstertotal > 1 and i.x == monsterarray[monstertotal - 1].x and i.y == monsterarray[monstertotal - 1].y and i.elevation == monsterarray[monstertotal - 1].elevation then 
								monstertotal = monstertotal - 1
							end
						end
						monsterdistance[monstertotal] = dist
						monsterarray[monstertotal] = i
					end
				end
			end
		end
		for i = 1, monstertotal do
			print(monsterarray[i].name, monsterdistance[i])
		end
	end,
}
If a monster is in a group. it compares it to the last monster added in the array, if they have the same coordinates, then the monstertotal decrements by -1, (after the increment earlier in the script meaning it will be overwriting the previous monster)
This means only the last monster in a group will be reported.

I had to add a check to make sure monstertotal is > 1 so we don't try to compare a nil value, which will crash the game.
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Monster Detector

Post by akroma222 »

Very cool!
I am trying to use that method in my script but it looks like a rewrite is in order
Will check back in when I have got it all sorted - thanks again!!!
GoldenShadowGS
Posts: 168
Joined: Thu Oct 30, 2014 1:56 am

Re: Monster Detector

Post by GoldenShadowGS »

Here is a updated script for the spell:

Code: Select all

defineSpell{
	name = "detect_monster",
	uiName = "Monster Detector",
	skill = "earth_magic",
	requirements = {"concentration", 1},
	gesture = 8,
	manaCost = 5,
	icon = 14,
	spellIcon = 13,
	description = "Reveals how many monster are nearby. Every point is Earth Magic increases your maximum detection range.",
	onCast = function(champion, x, y, direction, elevation, skillLevel)
		local monstertotal = 0
		--max range
		local count = 4 + skillLevel
		local monsterarray = {}
		local monsterdistance = {}
		local maxdist = 0
		--Fill the Monster Array
		for fx = x - count, x + count do
			for fy = y - count, y + count do
				for i in party.map:entitiesAt(fx,fy) do
					if i:getComponent("monster") then
						monstertotal = monstertotal + 1
						local xdist = (x - i.x) * 3
						local ydist = (y - i.y) * 3
						local zdist = (elevation - i.elevation) * 3
						local dist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
						if i.monster:getGroupSize() > 1 then
							if monstertotal > 1 and i.x == monsterarray[monstertotal - 1].x and i.y == monsterarray[monstertotal - 1].y and i.elevation == monsterarray[monstertotal - 1].elevation then 
								monstertotal = monstertotal - 1
							else
								monsterdistance[i] = dist
							end
						else
							monsterdistance[i] = dist
						end
						if dist > maxdist then
							maxdist = dist
						end
						monsterarray[monstertotal] = i
					end
				end
			end
		end
		for m = 1, maxdist do
			for k,v in pairs(monsterdistance) do
				if m == v then
					print(k.name,k.monster:getGroupSize(),v)
				end
			end
		end
	end,
}
It will print in order from closest to farthest the list of monsters, their group size and their distance.
GoldenShadowGS
Posts: 168
Joined: Thu Oct 30, 2014 1:56 am

Re: Monster Detector

Post by GoldenShadowGS »

Another tweak:

Code: Select all

defineSpell{
	name = "detect_monster",
	uiName = "Monster Detector",
	skill = "earth_magic",
	requirements = {"concentration", 1},
	gesture = 8,
	manaCost = 5,
	icon = 14,
	spellIcon = 13,
	description = "Reveals how many monster are nearby. Every point is Earth Magic increases your maximum detection range.",
	onCast = function(champion, x, y, direction, elevation, skillLevel)
		local monstertotal = 0
		--max range
		local count = 4 + skillLevel
		local monsterarray = {}
		local monsterdistance = {}
		local maxdist = 0
		--Fill the Monster Array
		for fx = x - count, x + count do
			for fy = y - count, y + count do
				for i in party.map:entitiesAt(fx,fy) do
					if i:getComponent("monster") then
						monstertotal = monstertotal + 1
						local xdist = (x - i.x) * 3
						local ydist = (y - i.y) * 3
						local zdist = (elevation - i.elevation) * 3
						local dist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
						if i.monster:getGroupSize() > 1 then
							if monstertotal > 1 and i.x == monsterarray[monstertotal - 1].x and i.y == monsterarray[monstertotal - 1].y and i.elevation == monsterarray[monstertotal - 1].elevation then 
								monstertotal = monstertotal - 1
							else
								monsterdistance[i] = dist
							end
						else
							monsterdistance[i] = dist
						end
						if dist > maxdist then
							maxdist = dist
						end
						monsterarray[monstertotal] = i
					end
				end
			end
		end
		local skillcount = 0
		for m = 1, maxdist do
			for k,v in pairs(monsterdistance) do
				if m == v then
					if skillcount < skillLevel then
						print(k.name,k.monster:getGroupSize(),v)
						skillcount = skillcount + 1
					end
				end
			end
		end
	end,
}
Now it only shows you one enemy per skill level in earth magic. If you have zero earth magic, it shows no enemies. If you have 3 points it shows 3 closest enemies, etc...
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Monster Detector

Post by akroma222 »

Brillant!!
I think Im over the idea of reporting back on (burning eg) conditions and what enemies traits are
This script will do very very nicely, thank you again GoldenShadowGS :D :D
Full credits for 3 detection (monster, secret, trap) spells are all yours
GoldenShadowGS
Posts: 168
Joined: Thu Oct 30, 2014 1:56 am

Re: Monster Detector

Post by GoldenShadowGS »

Did you one better:
Now it will display the correct names and plurals

Code: Select all

defineSpell{
	name = "detect_monster",
	uiName = "Monster Detector",
	skill = "earth_magic",
	requirements = {"concentration", 1},
	gesture = 8,
	manaCost = 5,
	icon = 14,
	spellIcon = 13,
	description = "Reveals how many monster are nearby. Every point is Earth Magic increases your maximum detection range.",
	onCast = function(champion, x, y, direction, elevation, skillLevel)
		local monsterNames = {air_elemental = "an Air Elemental", crab = "a Crab", crowern = "a Crowern", dark_acolyte = "a Dark Acolyte", 
		eyctopus = "an Eyectopus", fire_elemental = "a Fire Elemental", fjeld_warg = "a Fjeld Warg", fjeld_warg1 = "a Fjeld Warg",
		fjeld_warg2 = "a Fjeld Warg", forest_ogre = "a Forest Ogre", giant_snake = "a giant Snake", goromorg = "a Goromorg", 
		herder = "a Herder", herder_big = "a big Herder", herder_small = "a small Herder", ice_guardian = "an Ice Guardian", 
		lindworm = "a Lindworm", lizard_ice = "an Ice Lizard", lizard_dark = "a Dark Lizard", lizard_fire= "a Fire Lizard", 
		lizard_green = "a Green Lizard", magma_golem = "a Magma Golem", medusa = "a Medusa", mimic = "a Mimic", 
		mosquito_swarm = "a Swarm of Mosquitos", mummy = "a Mummy", mummy1 = "a Mummy", mummy2 = "a Mummy", mummy3 = "a Mummy", 
		ogre = "a Cave Ogre", rat_swarm = "a Swarm of Rats", ratling = "a Ratling", ratling1 = "a Ratling", ratling2 = "a Ratling", 
		ratling_boss = "a Ratling Clan Chief", sand_warg = "a Sand Warg", scavenger = "a Scavenger", shrakk_torr = "a Shrakk Torr",
		skeleton_archer = "a Skeleton Archer", skeleton_commander = "a Skeleton Commander", skeleton_trooper = "a Skeleton Trooper", 
		skeleton_trooper1 = "a Skeleton Trooper", skeleton_trooper2 = "a Skeleton Trooper", skeleton_warrior = "a Skeleton Warrior",
		slime_green = "a Green Slime", slime_red = "a Red Slime", slime_blue = "a Blue Slime", slime_fire = "a Fire Slime", 
		slime_ice = "an Ice Slime", slime_dark = "a Dark Slime", slime_plasm = "a Plasma Slime",  slime_poison = "a Poison Slime",  
		slime_golden = "a Golden Slime", snail = "a Snail", snail_blue_green = "a Hardshell Snail", snail_green_brown = "a Deep Forest Snail",
		spider = "a Spider", spore_mushroom = "a Mushroom Sporer", summon_stone = "a Summon Stone", swamp_toad = "a Swamp Toad",
		tentacles = "a Pit Tentacle", trickster = "a Trickster", turtle = "a Turtle", turtle_diving = "a Turtle", twigroot = "a Twigroot",
		uggardian = "a Uggardian", undead = "a Zombie", viper_root = "a Viper Root", warden = "a Warden", wizard = "a Wizard", wyvern = "a Wyvern",
		xeloroid = "a Xeloroid", zarchton_diving = "a Zarchton", zarchton = "a Zarchton"}
		local monsterNamesplural = {air_elemental = "Air Elementals", crab = "Crabs", crowern = "Crowerns", dark_acolyte = "Dark Acolytes", 
		eyctopus = "Eyectopuses", fire_elemental = "Fire Elementals", fjeld_warg = "Fjeld Wargs", fjeld_warg1 = "Fjeld Wargs",
		fjeld_warg2 = "Fjeld Wargs", forest_ogre = "Forest Ogres", giant_snake = "giant Snakes", goromorg = "Goromorgs", 
		herder = "Herders", herder_big = "big Herders", herder_small = "small Herders", ice_guardian = "Ice Guardians", 
		lindworm = "Lindworms", lizard_ice = "Ice Lizards", lizard_dark = "Dark Lizards", lizard_fire= "Fire Lizards", 
		lizard_green = "Green Lizards", magma_golem = "Magma Golems", medusa = "Medusas", mimic = "Mimics", 
		mosquito_swarm = "Swarm of Mosquitos", mummy = "Mummies", mummy1 = "Mummies", mummy2 = "Mummies", mummy3 = "Mummies", 
		ogre = "Cave Ogres", rat_swarm = "Swarm of Rats", ratling = "Ratlings", ratling1 = "Ratlings", ratling2 = "Ratlings", 
		ratling_boss = "Ratling Clan Chiefs", sand_warg = "Sand Wargs", scavenger = "Scavengers", shrakk_torr = "Shrakk Torrs",
		skeleton_archer = "Skeleton Archers", skeleton_commander = "Skeleton Commanders", skeleton_trooper = "Skeleton Troopers", 
		skeleton_trooper1 = "Skeleton Troopers", skeleton_trooper2 = "Skeleton Troopers", skeleton_warrior = "Skeleton Warriors",
		slime_green = "Green Slimes", slime_red = "Red Slimes", slime_blue = "Blue Slimes", slime_fire = "Fire Slimes", 
		slime_ice = "Ice Slimes", slime_dark = "Dark Slimes", slime_plasm = "Plasma Slimes",  slime_poison = "Poison Slimes",  
		slime_golden = "Golden Slimes", snail = "Snails", snail_blue_green = "Hardshell Snails", snail_green_brown = "Deep Forest Snails",
		spider = "Spiders", spore_mushroom = "Mushroom Sporers", summon_stone = "Summon Stones", swamp_toad = "Swamp Toads",
		tentacles = "Pit Tentacles", trickster = "Tricksters", turtle = "Turtles", turtle_diving = "Turtles", twigroot = "Twigroots",
		uggardian = "Uggardians", undead = "Zombies", viper_root = "Viper Roots", warden = "Wardens", wizard = "Wizards", wyvern = "Wyverns",
		xeloroid = "Xeloroids", zarchton_diving = "Zarchtons", zarchton = "Zarchtons"}
		local monstertotal = 0
		--max range
		local count = 4 + skillLevel
		local monsterarray = {}
		local monsterdistance = {}
		local maxdist = 0
		--Fill the Monster Array
		for fx = x - count, x + count do
			for fy = y - count, y + count do
				for i in party.map:entitiesAt(fx,fy) do
					if i:getComponent("monster") then
						monstertotal = monstertotal + 1
						local xdist = (x - i.x) * 3
						local ydist = (y - i.y) * 3
						local zdist = (elevation - i.elevation) * 3
						local dist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
						if i.monster:getGroupSize() > 1 then
							if monstertotal > 1 and i.x == monsterarray[monstertotal - 1].x and i.y == monsterarray[monstertotal - 1].y and i.elevation == monsterarray[monstertotal - 1].elevation then 
								monstertotal = monstertotal - 1
							else
								monsterdistance[i] = dist
							end
						else
							monsterdistance[i] = dist
						end
						if dist > maxdist then
							maxdist = dist
						end
						monsterarray[monstertotal] = i
					end
				end
			end
		end
		local skillcount = 0
		playSound("generic_spell")
		for m = 0, maxdist do
			for k,v in pairs(monsterdistance) do
				if m == v and skillcount < skillLevel then
					if k.monster:getGroupSize() <= 1 then
						hudPrint("There is "..monsterNames[k.name].." "..m.." meters away.")
						skillcount = skillcount + 1
					else
						hudPrint("There is a group of "..k.monster:getGroupSize().." "..monsterNamesplural[k.name].." "..m.." meters away.")
						--print(k.name,k.monster:getGroupSize(),v)
						skillcount = skillcount + 1
					end
				end
			end
		end
	end,
}
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Monster Detector

Post by akroma222 »

Well, nothing wrong with some friendly competition! ;)

Ive added an upgrade whereby if your caster has skill level = 3 then the print returns what direction the monster is in relation to the party and if they are beneath or above the party
(I figured this info could actually be useful and prevent you running into ambushes hehe)
SpoilerShow

Code: Select all

	
defineSpell{
   name = "detect_monster",
   uiName = "Monster Detector",
   skill = "earth_magic",
   requirements = {"concentration", 1},
   gesture = 8,
   manaCost = 5,
   icon = 14,
   spellIcon = 13,
   description = "Reveals how many monster are nearby. Every point is Earth Magic increases your maximum detection range.",
   onCast = function(champion, x, y, direction, elevation, skillLevel)

	local monsterNames = {air_elemental = "an Air Elemental", crab = "a Crab", crowern = "a Crowern", dark_acolyte = "a Dark Acolyte",
          eyctopus = "an Eyectopus", fire_elemental = "a Fire Elemental", fjeld_warg = "a Fjeld Warg", fjeld_warg1 = "a Fjeld Warg",
          fjeld_warg2 = "a Fjeld Warg", forest_ogre = "a Forest Ogre", giant_snake = "a giant Snake", goromorg = "a Goromorg",
          herder = "a Herder", herder_big = "a big Herder", herder_small = "a small Herder", ice_guardian = "an Ice Guardian",
          lindworm = "a Lindworm", lizard_ice = "an Ice Lizard", lizard_dark = "a Dark Lizard", lizard_fire= "a Fire Lizard",
          lizard_green = "a Green Lizard", magma_golem = "a Magma Golem", medusa = "a Medusa", mimic = "a Mimic",
          mosquito_swarm = "a Swarm of Mosquitos", mummy = "a Mummy", mummy1 = "a Mummy", mummy2 = "a Mummy", mummy3 = "a Mummy",
          ogre = "a Cave Ogre", rat_swarm = "a Swarm of Rats", ratling = "a Ratling", ratling1 = "a Ratling", ratling2 = "a Ratling",
          ratling_boss = "a Ratling Clan Chief", sand_warg = "a Sand Warg", scavenger = "a Scavenger", shrakk_torr = "a Shrakk Torr",
          skeleton_archer = "a Skeleton Archer", skeleton_commander = "a Skeleton Commander", skeleton_trooper = "a Skeleton Trooper",
          skeleton_trooper1 = "a Skeleton Trooper", skeleton_trooper2 = "a Skeleton Trooper", skeleton_warrior = "a Skeleton Warrior",
          slime_green = "a Green Slime", slime_red = "a Red Slime", slime_blue = "a Blue Slime", slime_fire = "a Fire Slime",
          slime_ice = "an Ice Slime", slime_dark = "a Dark Slime", slime_plasm = "a Plasma Slime",  slime_poison = "a Poison Slime", 
          slime_golden = "a Golden Slime", snail = "a Snail", snail_blue_green = "a Hardshell Snail", snail_green_brown = "a Deep Forest Snail",
          spider = "a Spider", spore_mushroom = "a Mushroom Sporer", summon_stone = "a Summon Stone", swamp_toad = "a Swamp Toad",
          tentacles = "a Pit Tentacle", trickster = "a Trickster", turtle = "a Turtle", turtle_diving = "a Turtle", twigroot = "a Twigroot",
          uggardian = "a Uggardian", undead = "a Zombie", viper_root = "a Viper Root", warden = "a Warden", wizard = "a Wizard", wyvern = "a Wyvern",
          xeloroid = "a Xeloroid", zarchton_diving = "a Zarchton", zarchton = "a Zarchton"}
          
	local monsterNamesplural = {air_elemental = "Air Elementals", crab = "Crabs", crowern = "Crowerns", dark_acolyte = "Dark Acolytes",
          eyctopus = "Eyectopuses", fire_elemental = "Fire Elementals", fjeld_warg = "Fjeld Wargs", fjeld_warg1 = "Fjeld Wargs",
          fjeld_warg2 = "Fjeld Wargs", forest_ogre = "Forest Ogres", giant_snake = "giant Snakes", goromorg = "Goromorgs",
          herder = "Herders", herder_big = "big Herders", herder_small = "small Herders", ice_guardian = "Ice Guardians",
          lindworm = "Lindworms", lizard_ice = "Ice Lizards", lizard_dark = "Dark Lizards", lizard_fire= "Fire Lizards",
          lizard_green = "Green Lizards", magma_golem = "Magma Golems", medusa = "Medusas", mimic = "Mimics",
          mosquito_swarm = "Swarm of Mosquitos", mummy = "Mummies", mummy1 = "Mummies", mummy2 = "Mummies", mummy3 = "Mummies",
          ogre = "Cave Ogres", rat_swarm = "Swarm of Rats", ratling = "Ratlings", ratling1 = "Ratlings", ratling2 = "Ratlings",
          ratling_boss = "Ratling Clan Chiefs", sand_warg = "Sand Wargs", scavenger = "Scavengers", shrakk_torr = "Shrakk Torrs",
          skeleton_archer = "Skeleton Archers", skeleton_commander = "Skeleton Commanders", skeleton_trooper = "Skeleton Troopers",
          skeleton_trooper1 = "Skeleton Troopers", skeleton_trooper2 = "Skeleton Troopers", skeleton_warrior = "Skeleton Warriors",
          slime_green = "Green Slimes", slime_red = "Red Slimes", slime_blue = "Blue Slimes", slime_fire = "Fire Slimes",
          slime_ice = "Ice Slimes", slime_dark = "Dark Slimes", slime_plasm = "Plasma Slimes",  slime_poison = "Poison Slimes", 
          slime_golden = "Golden Slimes", snail = "Snails", snail_blue_green = "Hardshell Snails", snail_green_brown = "Deep Forest Snails",
          spider = "Spiders", spore_mushroom = "Mushroom Sporers", summon_stone = "Summon Stones", swamp_toad = "Swamp Toads",
          tentacles = "Pit Tentacles", trickster = "Tricksters", turtle = "Turtles", turtle_diving = "Turtles", twigroot = "Twigroots",
          uggardian = "Uggardians", undead = "Zombies", viper_root = "Viper Roots", warden = "Wardens", wizard = "Wizards", wyvern = "Wyverns",
          xeloroid = "Xeloroids", zarchton_diving = "Zarchtons", zarchton = "Zarchtons"}
         
		 	local monstertotal = 0
         
          	local count = 4 + skillLevel
          	local monsterarray = {}
          	local monsterdistance = {}
          	local maxdist = 0
			
			local dir = ""
          	
          	for fx = x - count, x + count do
             	for fy = y - count, y + count do
                	for i in party.map:entitiesAt(fx,fy) do
                   		if i:getComponent("monster") then
                      		monstertotal = monstertotal + 1
                      		local xdist = (x - i.x) * 3
                      		local ydist = (y - i.y) * 3
                      		local zdist = (elevation - i.elevation) * 3
                      		local dist = math.floor(0.5 + math.sqrt(xdist^2 + ydist^2 + zdist^2))
                      		if i.monster:getGroupSize() > 1 then
                       			if monstertotal > 1 and i.x == monsterarray[monstertotal - 1].x and i.y == monsterarray[monstertotal - 1].y and i.elevation == monsterarray[monstertotal - 1].elevation then
                            		monstertotal = monstertotal - 1
                         		else
                            		monsterdistance[i] = dist
                         		end
		                   	else
                         		monsterdistance[i] = dist
                     	 	end
                      		if dist > maxdist then
	                        	maxdist = dist
                      		end
                      		monsterarray[monstertotal] = i
                   		end
                	end
             	end
          	end
          	local skillcount = 0
          	playSound("generic_spell")
          	for m = 0, maxdist do
             	for k,v in pairs(monsterdistance) do
                	if m == v and skillcount < skillLevel then
						
						--directly above or below
						if x == k.x and y == k.y then
							if x.elevation < k.elevation then
								dir = "directly above you"
							else
								dir = "directly below you"
							end
						--north
						elseif x == k.x and y > k.y then
							if elevation < k.elevation then
								dir = "above you to the north"
							elseif elevation > k.elevation then
								dir = "below you to the north"
							else
								dir = "to the north"
							end
						--north east
						elseif x < k.x and y > k.y then
							if elevation < k.elevation then
								dir = "above you to the north east"
							elseif elevation > k.elevation then
								dir = "below you to the north east"
							else
								dir = "to the north east"
							end
						--east
						elseif x < k.x and y == k.y then
							if elevation < k.elevation then
								dir = "above you to the east"
							elseif elevation > k.elevation then
								dir = "below you to the east"
							else
								dir = "to the east"
							end
						--south east
						elseif x < k.x and y < k.y then
							if elevation < k.elevation then
								dir = "above you to the south east"
							elseif elevation > k.elevation then
								dir = "below you to the south east"
							else
								dir = "to the south east"
							end
						--south
						elseif x == k.x and y < k.y then
							if elevation < k.elevation then
								dir = "above you to the south"
							elseif elevation > k.elevation then
								dir = "below you to the south"
							else
								dir = "to the south"
							end
						--south west
						elseif x > k.x and y < k.y then
							if elevation < k.elevation then
								dir = "above you to the south west"
							elseif elevation > k.elevation then
								dir = "below you to the south west"
							else
								dir = "to the south west"
							end
						--west
						elseif x > k.x and y == k.y then
							if elevation < k.elevation then
								dir = "above you to the west"
							elseif elevation > k.elevation then
								dir = "below you to the west"
							else
								dir = "to the west"
							end
						--north west
						elseif x > k.x and y > k.y then
							if elevation < k.elevation then
								dir = "above you to the north west"
							elseif elevation > k.elevation then
								dir = "below you to the north west"
							else
								dir = "to the north west"
							end
						end

                   		if k.monster:getGroupSize() <= 1 then
							if skillLevel >= 3 then
                      			hudPrint("There is "..monsterNames[k.name].." "..m.." meters away, "..dir..".")
                      			skillcount = skillcount + 1
							else
								hudPrint("There is "..monsterNames[k.name].." "..m.." meters away.")
                      			skillcount = skillcount + 1
							end
                   		else
							if skillLevel >= 3 then
                      			hudPrint("There is a group of "..k.monster:getGroupSize().." "..monsterNamesplural[k.name].." "..m.." meters away, "..dir..".")
                      			--print(k.name,k.monster:getGroupSize(),v)
                     			skillcount = skillcount + 1
							else
								hudPrint("There is a group of "..k.monster:getGroupSize().." "..monsterNamesplural[k.name].." "..m.." meters away.")
                      			--print(k.name,k.monster:getGroupSize(),v)
                     			skillcount = skillcount + 1
							end
                   		end
                	end
             	end
          	end
       	end
Good times!
Akroma :)
GoldenShadowGS
Posts: 168
Joined: Thu Oct 30, 2014 1:56 am

Re: Monster Detector

Post by GoldenShadowGS »

I like it, but for playability, perhaps we should tell the player the direction relative to the party instead of a compass direction.
If you know the monster is north of the player, then you can use the "direction" variable to figure out which way you are facing relative to north.

Example: Monster is to the north, player is facing west:
"There is a monster to our Right"

Edit:Working on a script for this...
Post Reply