Is there any way to script tool interaction with tiles/objects? I have looked through "beamaxe.beamaxe", "beamaxe.lua" and "copperpickaxe.miningtool", but it doesn't help. For example, I would like to create a tool, which can interact with objects only, but has no effect, when affects tiles. Is it possible?
You'd want an active item. You can scan for things at the location of the cursor when clicking. Code: #### `List<EntityId>` world.entityQuery(`Vec2F` position, `Variant<Vec2F, float` positionOrRadius, [`Json` options]) Queries for entities in a specified area of the world and returns a list of their entity ids. Area can be specified either as the `Vec2F` lower left and upper right positions of a rectangle, or as the `Vec2F` center and `float` radius of a circular area. The following additional parameters can be specified in options: * __withoutEntityId__ - Specifies an `EntityId` that will be excluded from the returned results * __includedTypes__ - Specifies a list of one or more `String` entity types that the query will return. In addition to standard entity type names, this list can include "mobile" for all mobile entity types or "creature" for players, monsters and NPCs. * __boundMode__ - Specifies the bounding mode for determining whether entities fall within the query area. Valid options are "position", "collisionarea", "metaboundbox". Defaults to "collisionarea" if unspecified. * __order__ - A `String` used to specify how the results will be ordered. If this is set to "nearest" the entities will be sorted by ascending distance from the first positional argument. If this is set to "random" the list of results will be shuffled. * __callScript__ - Specifies a `String` name of a function that should be called in the script context of all scripted entities matching the query. * __callScriptArgs__ - Specifies a list of arguments that will be passed to the function called by callScript. * __callScriptResult__ - Specifies a `LuaValue` that the function called by callScript must return; entities whose script calls do not return this value will be excluded from the results. Defaults to `true`. --- Similarly you can use world.objectQuery() since you only want objects. If you where trying to damage only objects, you could them spawn a projectile at that point, which may or may not be visible depending upon your preferences. If you are trying to do something else, you can use the messaging system. Or as you see, the world.entityQuery() or world.objectQuery() can call a script from that object too. An example of an object that uses this is doors. /objects/wired/door/door.lua Code: function hasCapability(capability) if capability == 'lockedDoor' then return storage.locked elseif object.isInputNodeConnected(0) or storage.locked or self.sensorConfig then return false elseif capability == 'door' then return true elseif capability == 'closedDoor' then return not storage.state elseif capability == 'openDoor' then return storage.state else return false end end So to show you how that gets used, /scripts/actions/movement.lua Code: function openDoors(args, board) local direction = args.direction or mcontroller.facingDirection() --Default to opening doors in front local position = mcontroller.position() local bounds = rect.translate(mcontroller.boundBox(), mcontroller.position()) local opened = true if direction > 0 then bounds[1] = bounds[3] bounds[3] = bounds[3] + args.distance else bounds[3] = bounds[1] bounds[1] = bounds[1] - args.distance end if world.rectTileCollision(bounds, {"Dynamic"}) then opened = false -- There is a colliding object in the way. See if we can open it local closedDoors = world.entityQuery(rect.ll(bounds), rect.ur(bounds), { includedTypes = {"object"}, callScript = "hasCapability", callScriptArgs = { "closedDoor" } }) util.debugRect(bounds, "blue") if args.openLocked then local lockedDoors = world.entityQuery(rect.ll(bounds), rect.ur(bounds), { includedTypes = {"object"}, callScript = "hasCapability", callScriptArgs = { "lockedDoor" } }) closedDoors = util.mergeLists(closedDoors, lockedDoors) end for _, doorId in pairs(closedDoors) do local toDoor = world.distance(world.entityPosition(doorId), mcontroller.position()) if toDoor[1] * direction > 0 then world.callScriptedEntity(doorId, "openDoor") opened = true end end end return opened end So that will scan for objects in the rectangle in front of the entity itself. It will then call hasCapability() - which only is gonna work on objects that have that function call. If the function call doesn't exist or if it doesn't get a return of true, then world.entityQuery() won't return that particular object. They are then using world.callScriptedEntity() to call openDoor() - itself within doors.lua So you see there are multiple ways for one entity to trigger the function call of another.
Thank you, your answer is great. I have tried something like it before, but I made it through .minningtool, fireableItem. It works the same, I think. I set "tileDamage" to 0 to disable default resource extracting. I used world.entityQuery and fireableItem.ownerAimPosition to get an entity, a player is aiming at. But it doesn't really work accurate. The player was aiming at the dirt tile under a tree and grass, but world.entityQuery said, there are three entities: the plyaer themself, the tree and some grass. Maybe, I am doing something wrong about it? Is there any way, I can know what is the only one entity, player aiming at? world.objectAt doesn't work, because a tree isn't an object, I tried it.