Ask a simple question, get a simple answer

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: 2780
Joined: Mon Sep 23, 2013 2:24 am

Re: Ask a simple question, get a simple answer

Post by minmay »

On second examination, you're right - the underwater fog is tied to the presence of a WaterSurfaceMesh. So instead, add a WaterSurfaceMeshComponent to your water object, but give it a dummy transparent material like:

Code: Select all

{
	-- builds a continuous mesh from underwater tiles
	class = "WaterSurfaceMesh",
	material = "nothing",
	underwaterMaterial = "nothing",
},

Code: Select all

defineMaterial{
	name = "nothing",
	diffuseMap = "assets/textures/common/black_translucent.tga",
	doubleSided = false,
	alphaTest = true,
	lighting = false,
	ambientOcclusion = false,
	castShadow = false,
	blendMode = "Opaque",
	textureAddressMode = "Wrap",
	glossiness = 0,
	depthBias = 0,
}
I don't think this will hurt performance significantly and it will give you the underwater fog etc.
Remember not to put more than one WaterSurfaceComponent on one level, doing so can take away the fog (and has a variety of other undesirable effects).
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.
User avatar
Illidan
Posts: 19
Joined: Sat Mar 12, 2016 3:23 pm
Location: Germany

Re: Ask a simple question, get a simple answer

Post by Illidan »

Is there any way to bypass the projectileCollider of closed portculli-doors with only Arrows, Shuriken, Darts and small Rocks? I want my party to throw them through the portcullis, but spells, all other items, party and monsters shall still be blocked.
I already tried diverse combinations of "collisionGroup" on doors and "collisionMask" for the items (collisionMask can only be used on projectiles like spells, for items I get an error). So it doesn't work the way I want it. But perhaps I did something wrong?
Invisible teleporters are also no solution, they would transport ALL items and it looks strange, too.
Perhaps a script placed in front and behind of a door, which deactivates the projectileCollider only for Shuriken, Darts, Arrows and small Rocks?
Please notice I am still a novice to scripting! :roll:
But perhaps you have a better solution then my idea... :)
minmay
Posts: 2780
Joined: Mon Sep 23, 2013 2:24 am

Re: Ask a simple question, get a simple answer

Post by minmay »

Illidan wrote:I already tried diverse combinations of "collisionGroup" on doors and "collisionMask" for the items (collisionMask can only be used on projectiles like spells, for items I get an error). So it doesn't work the way I want it. But perhaps I did something wrong?
It sounds like you're trying to add the collisionMask field to the ItemComponent, instead of the ProjectileComponent that is created when the item is thrown. To do that the best you can do is probably adding the following component:

Code: Select all

{
  class = "Timer",
  name = "cmtimer",
  timerInterval = 0,
  currentLevelOnly = true,
  onActivate = function(self)
    if self.go.projectile then self.go.projectile:setCollisionMask(3) end
  end,
}
It would be very expensive to add this to all items in the dungeon, which is necessary for what you are trying to do - you need to, at a minimum, add a bit to the collision mask of every projectile in the game other than the 4 you want to be thrown through the portcullis (otherwise you have to remove collision from those 4 entirely). This is not a good solution.
You could check the two squares in front of and behind the portcullis every frame, looking for projectiles and changing their collision masks appropriately, but this is also not a good solution (aside from being expensive, albeit not nearly as much as the first option, it won't work on projectiles that are fast enough that they don't spend any frames in that square before hitting the door).
If you only care about projectiles created by the party it doesn't really make things much easier because there's no way to detect a throw (thrown items can be stopped before spending a single frame in the air).

I don't think your desired feature is worth the number and scope of problems that it introduces.

However, your question does bring to mind the only use for ProjectileImpactComponent: applying an effect to a thrown item hitting a non-monster entity, without having to detect when it is thrown (something that can really only be done with a once-every-frame timer, which will be expensive if you have a lot of items). Unfortunately, the item lands before onHitEntity (or WallTriggerComponent.onActivate) fires, so the projectile is already gone, and the item is already on the ground. The only exception is if you add a BombItemComponent to the object, in which case ProjectileImpactComponent.onHitEntity is called right after BombCompoent.onExplode but before the ProjectileComponent is destroyed. But since BombItemComponent unavoidably destroys the item immediately after that (disabling it doesn't stop it from destroying the object) this introduces more problems than it solves. You can make the object look like it's flying through the portcullis by spawning a new, identical object when it explodes, but then for all other collisions (and ProjectileImpactComponent can't catch collisions with solid tiles/floor/etc, you need ProjectileComponent.onProjectileHit) you need to spawn a new object that's identical except missing the BombComponent (so it can actually land without exploding) then spawn another new object with the BombComponent (onExplode hook or a valid bomb type is needed to avoid console warnings, and you don't want to give it a valid bomb type) when the object could potentially be thrown again (probably when it gets picked up again, or right after it lands).

Consider using several narrow vertical ProjectileColliders instead so that only small objects can be thrown through, and move them when the door opens or closes.

If you are okay with a nasty visual jump and an impact sound, you could use ProjectileImpactComponent without the BombItemComponent; if it collides with a sparse door, re-throw it with the sparse door ignored. Example:

Code: Select all

do
local smallItems = {"arrow","shuriken","dart","rock"}
for _,itm in ipairs(smallItems) do
defineObject{
	name = itm,
	baseObject = itm,
	components = {
		{
			class = "ProjectileImpact",
			onHitEntity = function(self, entity)
				for _,c in entity:componentIterator() do
					if c.getSparse and c:getSparse() then
						self.go.item:throwItem(self.go.facing,14)
						local wpos = self.go:getWorldPosition()
						wpos[2] = entity:getWorldPositionY()+1.4

						-- These three lines are optional; they
						-- move the item a bit past the door so that
						-- they do not hit the party if the party
						-- threw the item at an adjacent door (no
						-- support for more than one ignoreEntity)
						local ax = self.go.facing%2 == 1 and 1 or 3
						local sgn = (self.go.facing==2 or self.go.facing==3) and -1 or 1
						wpos[ax] = wpos[ax]+0.5*sgn

						self.go:setWorldPosition(wpos)
						self.go.projectile:setIgnoreEntity(entity)
						self.go.projectile:setFallingVelocity(0)
						self.go.projectile:setGravity(1)
						return
					end
				end
			end,
		},
	},
}
end
end
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.
User avatar
Illidan
Posts: 19
Joined: Sat Mar 12, 2016 3:23 pm
Location: Germany

Re: Ask a simple question, get a simple answer

Post by Illidan »

@minmay:
Wow, I am VERY impressed how much you know about the engine mechanics and about scripting! :shock:
Thanx again for your help!

I did not think that it would be THAT complicated with the Items. :roll:
I think I will try your TimerClass-script and do expensive work. I do not give up so easily. :?
Also, I will try your idea with using several narrow vertical ProjectileColliders so that only small objects can be thrown through.
minmay
Posts: 2780
Joined: Mon Sep 23, 2013 2:24 am

Re: Ask a simple question, get a simple answer

Post by minmay »

Illidan wrote:I think I will try your TimerClass-script and do expensive work.
Please don't. By "expensive", I don't just mean that it will take a lot of work. I mean that it will kill performance in your dungeon. And remember that you need to do this for ALL projectiles, not just items, so that means redefining all the spell projectiles, etc.
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.
User avatar
Illidan
Posts: 19
Joined: Sat Mar 12, 2016 3:23 pm
Location: Germany

Re: Ask a simple question, get a simple answer

Post by Illidan »

Finally, I found a solution.
It was quite... complicated to find out. :shock:

You only need to outfit the four items Shuriken, Darts, Rocks and Arrows with a CollisionMask. And you have to manually disable the cmtimer-checkmark when you have placed the item in your dungeon so that the timer does not count right from the beginning.
I placed a lot of the four items im my dungeon and threw them around and measured with Fraps if it will kill performance. There is no measured Framedrop so I think the combined solution of minmay and me is good. :)

Here is the solution.

For example: the Shuriken. (Do the same to Rocks, Darts and Arrows)
Put this script in your weapons.lua:
SpoilerShow
defineObject{
name = "dm_shuriken",
baseObject = "base_item",
components = {
{
class = "Model",
model = "assets/models/items/shuriken.fbx",
},
{
class = "Item",
uiName = "Shuriken",
gfxIndex = 12,
gfxIndexPowerAttack = 447,
impactSound = "impact_blade",
stackable = true,
sharpProjectile = true,
projectileRotationSpeed = 12,
projectileRotationX = 90,
projectileRotationY = -90,
weight = 0.1,
traits = { "throwing_weapon" },
secondaryAction = "volley",
},
{
class = "Timer",
name = "cmtimer",
timerInterval = 0,
DisableSelf = true,
TriggerOnStart = false,
CurrentLevelOnly = true,
CurrentLevelOnly = true,
onActivate = function(self)
if self.go.projectile then self.go.projectile:setCollisionMask(4) end
end,
},

{
class = "ThrowAttack",
attackPower = 13,
cooldown = 3.5,
},
{
class = "ThrowAttack",
uiName = "Volley of Stars",
name = "volley",
attackPower = 14,
cooldown = 3.5,
energyCost = 30,
repeatCount = 3,
spread = 0.4,
requirements = { "throwing", 3 },
gameEffect = "Quickly throw three shurikens at once."
},
},
tags = { "weapon", "weapon_throwing" },
}
Now, every door will ignore the four items with the collisionMask 4. BUT, we want this ONLY on portculli-doors to happen, so for all other massive doors we need an additionally doorCollider.
Therefore you need a ProjectileCollider with the same collisionGroup 4.
Put this in your trigger.lua or door.lua or whatever lua-file you prefere for this:
SpoilerShow
defineObject{
name = "dm_throw_collider",
components = {
{
class = "ProjectileCollider",
collisionGroup = 4,
size = vec(2.5, 3, 0.5),
offset = vec(0, 1.5, 0.7),
debugDraw = true,
},
{
class = "Controller",
onActivate = function(self)
self.go.projectilecollider:enable()
end,
onDeactivate = function(self)
self.go.projectilecollider:disable()
end,
onToggle = function(self)
if self.go.projectilecollider:isEnabled() then
self.go.projectilecollider:disable()
else
self.go.projectilecollider:enable()
end
end,
},
},
placement = "wall",
editorIcon = 72,
}
Than place the new ProjectileCollider-object on the doors in the editor you don't want to let pass the four thrown items (perhaps you have to play around a little with the size- and offset-vectors of the "dm-throw-collider").
And now, one important thing:
You can only deactivate the "dm_throw_collider" by a button or lever or a script. And you must deactivate the collider or all four items are still blocked when the door is open! I have no "PullChain"-object on my doors, instead I have a separate custom door button sitting on my doorframe to open and close the door. You have to connect the custom button with the door and the "dm_throw_collider". When you press the door-button, it toggles the door open and toggles (deactivates) the "dm-throw-collider". When you press again, the door closes and activates the "dm-throw-collider" again.

That's it! :D
Perhaps, there is a more confortable way to reach this goal, but I have not found out yet. ;)
If anybody has a better solution, your ideas are very welcome!
But for me, my goal is satisfactorily reached. 8-)
minmay
Posts: 2780
Joined: Mon Sep 23, 2013 2:24 am

Re: Ask a simple question, get a simple answer

Post by minmay »

Sorry, but that solution will not work. The first collision bit is used for collision with almost everything, not just doors: obstacles, monsters, the party, etc. You would need to add additional ProjectileColliders to all obstacles, monsters, etc. to use your approach. ProjectileColliderComponent does support parentNode, so for monsters I think you can give it the capsule node as its parent and the proper size/offset and it will work fine, but you'd have to figure out more about capsule behaviour than I know.

Also your timer changes stop the timer from working properly altogether. It needs to run on every update on the current level. Consider what happens when you throw the item more than once.

Obviously adding a timer to every item won't kill performance if your dungeon does not have very many items, but I routinely see people putting huge numbers of items in their dungeon, which means huge numbers of TimerComponents all of which have to be updated and all of which have to be serialized when the game is saved.
Last edited by minmay on Sun Apr 03, 2016 3:55 am, edited 1 time in total.
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.
User avatar
Illidan
Posts: 19
Joined: Sat Mar 12, 2016 3:23 pm
Location: Germany

Re: Ask a simple question, get a simple answer

Post by Illidan »

Oh my... it could have been so easy. :(
Okay, you are right, minmay. I've tested it and the items collide with almost everything. :o
I will search for an other solution tomorrow. I am still learning...
Thanx anyway.
User avatar
THOM
Posts: 1274
Joined: Wed Nov 20, 2013 11:35 pm
Location: Germany - Cologne
Contact:

Re: Ask a simple question, get a simple answer

Post by THOM »

I am still working on my function to remove all weappons from the party.

It works now so far - the only thing which doesn't: I do not get my weaptrait-table into the hasTrait call. What do I do wrong?

Code: Select all

function removeWeappons()

local weaptrait = {"light_weapon", "sword", "daggers", "weapon", "heavy_weapon", "mace", "axe", "two_handed", "firearm", "spear", "missile_weapon", "throwing_weapon", "wand" }  --13

	for i=1,4 do
		local ch = party.party:getChampion(i)
		for slot=1,ItemSlot.MaxSlots do
         		local item = ch:getItem(slot)
         		if item and item:hasTrait(weaptrait) then 
            			if item:getStackSize() < 0 then 
               				item:setStackSize(0)         				    
            			else
					ch:removeItemFromSlot(slot);  
            			end
         		end
		end
	end
end
THOM formaly known as tschrage
_______________________________________________
My MOD (LoG1): Castle Ringfort Thread
My MOD (LoG2): Journey To Justice Thread | Download
User avatar
AndakRainor
Posts: 674
Joined: Thu Nov 20, 2014 5:18 pm

Re: Ask a simple question, get a simple answer

Post by AndakRainor »

Code: Select all

function removeWeappons()

  local weaptrait = {"light_weapon", "sword", "daggers", "weapon", "heavy_weapon", "mace", "axe", "two_handed", "firearm", "spear", "missile_weapon", "throwing_weapon", "wand" }  --13

  for i=1,4 do
    local ch = party.party:getChampion(i)
    for slot=1,ItemSlot.MaxSlots do
      local item = ch:getItem(slot)
      if item then
        for _,trait in ipairs(weaptrait)
          if item:hasTrait(trait) then 
            ch:removeItemFromSlot(slot)
            break
          end
        end
      end
    end
  end
end
warning: I found at least one weapon without any trait in the assets pack; torch and torch_everburning
Post Reply