I FIXED LITERALLY EVERYTHING!

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!
User avatar
lyle_drake
Posts: 20
Joined: Fri Jan 16, 2015 7:53 pm

I FIXED LITERALLY EVERYTHING!

Post by lyle_drake »

I did it, this game is finally playable.
What, may i ask, would you say is the weakest part of the gameplay experience of The Legend of Grimrock?
That's right; the combat.
Fights against single enemies are slow and boring. Strafing around a big enemy for two minutes straight is absolutely no fun at all.
You have too much mobility while attacking, and too much attacking potential while moving.

So i fixed both of those things.
BEHOLD MY MAGNIFICENCE!

Code: Select all

defineObject{
	name = "party",
	components = {
		{
			class = "Party",
			onMove = function(self)
				local c = self:getChampion(1)
				for i=1,4 do
					if self:getChampion(i):isAlive() then
						c = self:getChampion(i)
					end
				end
				if c:hasCondition("fighting") then
					return false
				else
					for i=1,4 do
						c = self:getChampion(i)
						c:setConditionValue("moving",1)
					end
				end
			end,
			onAttack = function(self)
				local c = self:getChampion(1)
				for i=1,4 do
					if self:getChampion(i):isAlive() then
						c = self:getChampion(i)
					end
				end
				if c:hasCondition("moving") then
					return false
				else
					for i=1,4 do
						c = self:getChampion(i)
						c:setConditionValue("fighting",1)
					end
				end
			end,
			onCastSpell = function(self)
				local c = self:getChampion(1)
				for i=1,4 do
					if self:getChampion(i):isAlive() then
						c = self:getChampion(i)
					end
				end
				if c:hasCondition("moving") then
					return false
				else
					for i=1,4 do
						c = self:getChampion(i)
						c:setConditionValue("fighting",1)
					end
				end
			end,
		},
		{
			class = "Light",
			name = "torch",
			range = 12,
		},
	},
	editorIcon = 32,
	placement = "floor",
}

defineCondition{
	name = "fighting",
	uiName = "Fighting",
	description = "Can't move.",
	icon = 9,
	beneficial = false,
	harmful = false,
	tickInterval = 1,
}

defineCondition{
	name = "moving",
	uiName = "Moving",
	description = "Can't fight.",
	icon = 9,
	beneficial = false,
	harmful = false,
	tickInterval = 1,
}
Can't move while attacking, can't attack while moving.
BOOM! Problem solved. Why did nobody do this earlier i wonder?

There.. IS a catch, though.
It doesnt work with unarmed attacks.
Goodness knows why, maybe the on attack hook relies on the on attack hook from the item component? no idea. Anyway, we can just call it martial arts and pretend it's a feature. I'm sure that'll be fine.

Anyway, no need to thank me, you're quite welcome. just take this sh*t and go make some dungeons with it. maybe tweak the condition durations first, though, the moving one seems a bit too intrusive.

BTW, i conjured up a quick preview of the system on the steam workshop.
http://steamcommunity.com/sharedfiles/f ... 1108257639
Last edited by lyle_drake on Sun Aug 13, 2017 10:03 am, edited 1 time in total.
User avatar
Isaac
Posts: 3188
Joined: Fri Mar 02, 2012 10:02 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by Isaac »

lyle_drake wrote: Why did nobody do this earlier i wonder?
I'd personally find it annoying, and don't mind the two-step dance; though I'd welcome an AI based change in the mechanics to make it harder to step-n-stab the opponents.

However... There is a terser way to achieve this effect:

Code: Select all

defineTrait{
	name = "attackCheck",
	uiName = "attackCheck",
	description = "",
	hidden = true, 
	onComputeAccuracy = function(champion)
							 if party.party:isMoving() then
							  return -1000
							 end
							end
}

defineObject{
	name = "party",
	baseObject = "party",
	components = { {   class = "Party",
			onAttack = function(self) self:grapple(.8) end, 
			onCastSpell = function(self, champion, spell)
							 self:grapple(.6)
							 if self:isMoving() then
							  champion:showAttackResult("Fizzle", "SpellFizzle")
							  playSound("spell_fizzle")
							  return false
							 end
							end,
			onInit = function(self) for x = 1, 4 do self:getChampion(x):addTrait("attackCheck") end end	
		}, 
	} 
}
It's possible to detect an unarmed_attack, but [afaik] it cannot actually be canceled. So this doesn't detect... it just applies a -1000 to all attacks made while in motion. With given the intent being a stand-up fight, it also imposes a brief immobility with each attack; and spells automatically fizzle when the party is in motion.
User avatar
lyle_drake
Posts: 20
Joined: Fri Jan 16, 2015 7:53 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by lyle_drake »

Huh. you sure showed up my kludged code, didn't ya? That's cool. I'm not even gonna pretend i'm a good scripter, nice to have someone who's been around for a while show me how it's done. :)
Isaac wrote: I'd personally find it annoying, and don't mind the two-step dance
I guess you can get used to anything, given enough exposure. But i remember completely aborting my first playthrough of Grimrock 1 purely because the combat was so dull. Each to their own, i suppose.

Anyway, thanks again for the significantly better code. I'mma implement it into this thing i'm working on, if you don't mind. Or maybe i'll integrate some of it into my own code and use that instead, i like how the conditions indicate to the player exactly what's going on, rather than having to front load the dungeon with a lengthy explanation of the new system. We'll see.
Last edited by lyle_drake on Sun Aug 13, 2017 10:33 am, edited 1 time in total.
User avatar
Isaac
Posts: 3188
Joined: Fri Mar 02, 2012 10:02 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by Isaac »

It's not one-up-manship... It is that the less complex it can be made (while still being functional), the better; in most cases.
It's easier to test; and often less problematic.
lyle_drake wrote:i like how the conditions indicate to the player exactly what's going on, rather than having to front load the dungeon with a lengthy explanation of the new system. We'll see.
It is possible to include an explanation. (I had this in my first version of the above script; but took it out because of the need to detect unarmed attacks—and with no way to cancel them.)

Code: Select all

defineTrait{
   name = "attackCheck",
   uiName = "attackCheck",
   description = "",
   hidden = true, 
   onComputeAccuracy = function(champion)
                      if party.party:isMoving() then
                       return -1000
                      end
                     end
}

defineObject{
   name = "party",
   baseObject = "party",
   components = { {   class = "Party",
         onAttack = function(self, champion) self:grapple(.8)
         				if self:isMoving() then
                       		champion:showAttackResult("Not while\nmoving!", "SpellFizzle")
                       		return false
                      	end
         			 end, 
         onCastSpell = function(self, champion, spell)
                      self:grapple(.6)
                      if self:isMoving() then
                       champion:showAttackResult("Fizzle", "SpellFizzle")
                       playSound("spell_fizzle")
                       return false
                      end
                     end,
         onInit = function(self) for x = 1, 4 do self:getChampion(x):addTrait("attackCheck") end end   
      }, 
   } 
}
User avatar
lyle_drake
Posts: 20
Joined: Fri Jan 16, 2015 7:53 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by lyle_drake »

isaac wrote:It's not one-up-manship...
What? no, why would...?
Oh, i see. The language barrier. Yeah, it's pretty american to assume i meant it competitively. Nah, I meant it more like i'm not very good at this, and then you, having way more skill and experience, showed me how to do it way better... I see how you could have misinterpreted that. Whatever, no harm done.

Anyway, this is some real good stuff you got there. i had hooked some explinations up using printHud, but it makes way more sense to just stick it on a showAttackResult instead. Still not a fan of using grapple to stop the player from moving, the animations when the player tries to move, combined with the sound effects that play all seem intent on making the player feel uncomfortable, which makes sense, considering where grapple was used in the main game.

A'ight, i'm off to make a dungeon, see if i can't make this work somehow. Couldn't have done it without ya, mate! :D Well, i probably could have, but it wouldn't've ended up being nearly as good.
User avatar
Isaac
Posts: 3188
Joined: Fri Mar 02, 2012 10:02 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by Isaac »

lyle_drake wrote:Still not a fan of using grapple to stop the player from moving, the animations when the player tries to move, combined with the sound effects that play all seem intent on making the player feel uncomfortable, which makes sense, considering where grapple was used in the main game.
Grapple can be replaced by —a lot more scripting ;)
(And with the caveat of paralyzing the party while any of them is still recovering from their attacks; I am not a fan of this part...I think it will be a problem for weapons with long cooldowns. The party needs to be agile; especially in a dynamic hostile environment full of trap-doors and flying projectiles.)

Code: Select all

defineTrait{
   name = "attackCheck",
   uiName = "attackCheck",
   description = "",
   hidden = true, 
   onComputeAccuracy = function(champion)
                      if party.party:isMoving() then
                       return -1000
                      end
                     end
}

defineObject{
   name = "party",
   baseObject = "party",
   components = { {   class = "Party",
         onAttack = function(self, champion)
         				if self:isMoving() then
                       		champion:showAttackResult("Not while\nmoving!", "SpellFizzle")
                       		return false
                      	end
         			 end, 
         onMove = function(self)
         						local dX, dY = getForward(party.facing)
         						local X, Y = party.x+dX,party.y+dY  	
	         					for x = 1, 4 do	
	         						 local champion = party.party:getChampion(x)
	         						 if not champion:isReadyToAttack(1) or
	         						 	not champion:isReadyToAttack(1) then
			         					for each in party.map:entitiesAt(X, Y) do  --This is to limit combat immobility to only when facing an opponent.
			         					 	if each.monster then
			         					 		champion:showAttackResult("Not while\nin combat!", "SpellFizzle")
			         					 	   return false
			         					 	end
			         					end	   
		         				     end
	         					end	 	 
         					 end,				 			 
         onCastSpell = function(self, champion, spell)
                      if self:isMoving() then
                       champion:showAttackResult("Fizzle", "SpellFizzle")
                       playSound("spell_fizzle")
                       return false
                      end
                     end,
         onInit = function(self) for x = 1, 4 do self:getChampion(x):addTrait("attackCheck") end end   
      }, 
   } 
}
User avatar
lyle_drake
Posts: 20
Joined: Fri Jan 16, 2015 7:53 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by lyle_drake »

Woah, this is weird.
So, i made a thing. a big, lengthy, thing full of nasties that you can't strafe around. And then i want to test it, right, so i exported it and went to make a basic party to run through it with, and the game crashed upon before i could get to the party creation screen. It said something about "onComputeAccuracy", so i messed around with some things, and noticed that the accuracy reduction was affecting the champions even when they didn't have the trait. Is that supposed to happen?

Anyway, i added an "if champion:hasTrait", and it seems fine now.
User avatar
Isaac
Posts: 3188
Joined: Fri Mar 02, 2012 10:02 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by Isaac »

lyle_drake wrote:Is that supposed to happen?
It's not intended to, no. I'm glad it works with the additional (seemingly very redundant) check. 8-)
User avatar
lyle_drake
Posts: 20
Joined: Fri Jan 16, 2015 7:53 pm

Re: I FIXED LITERALLY EVERYTHING!

Post by lyle_drake »

YEAH, i finished a thing!
I'd almost forgotten how time consuming dungeon making was.
Anyway, i'm loving how this turned out. Thanks for the help! :D

http://steamcommunity.com/sharedfiles/f ... 1120848896
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: I FIXED LITERALLY EVERYTHING!

Post by akroma222 »

Lyle_drake,
Your combat tweaking suggestions & changes above actually got me thinking on a modded combat system similar to the way Might Magic X handles it
Ill post up an idea discussion soon
Congrats on getting your dungeon out there!
Akroma
Post Reply