2022-07-17 23:32:44 +00:00
-- Copyright (c) 2022 David Vogel
--
-- This software is released under the MIT License.
-- https://opensource.org/licenses/MIT
2022-07-23 18:43:04 +00:00
local ComponentAPI = require ( " noita-api.component " )
local JSON = require ( " noita-api.json " )
2022-07-18 09:47:59 +00:00
-------------
-- Classes --
-------------
2022-07-17 23:32:44 +00:00
local EntityAPI = { }
---@class NoitaEntity
---@field ID integer -- Noita entity ID.
local NoitaEntity = { }
NoitaEntity.__index = NoitaEntity
2022-07-22 19:31:40 +00:00
EntityAPI.MetaTable = NoitaEntity
2022-07-17 23:32:44 +00:00
2022-07-26 14:33:29 +00:00
---Wraps the given entity ID and returns a Noita entity object.
2022-07-23 15:36:21 +00:00
---@param id number|nil
2022-07-18 20:53:34 +00:00
---@return NoitaEntity|nil
2022-07-26 14:33:29 +00:00
function EntityAPI . Wrap ( id )
2022-07-18 20:53:34 +00:00
if id == nil or type ( id ) ~= " number " then return nil end
return setmetatable ( { ID = id } , NoitaEntity )
end
2022-07-18 09:47:59 +00:00
------------------------
-- Noita API wrappers --
------------------------
2022-07-17 23:32:44 +00:00
---
---@param filename string
---@param posX number -- X coordinate in world (virtual) pixels.
---@param posY number -- Y coordinate in world (virtual) pixels.
---@return NoitaEntity|nil
2022-08-07 20:31:09 +00:00
function EntityAPI . Load ( filename , posX , posY ) -- TODO: Change to use Vec2 object
2022-07-26 14:33:29 +00:00
return EntityAPI.Wrap ( EntityLoad ( filename , posX , posY ) )
2022-07-17 23:32:44 +00:00
end
---
---@param filename string
---@param posX number -- X coordinate in world (virtual) pixels.
---@param posY number -- Y coordinate in world (virtual) pixels.
---@return NoitaEntity|nil
2022-08-07 20:31:09 +00:00
function EntityAPI . LoadEndGameItem ( filename , posX , posY ) -- TODO: Change to use Vec2 object
2022-07-26 14:33:29 +00:00
return EntityAPI.Wrap ( EntityLoadEndGameItem ( filename , posX , posY ) )
2022-07-17 23:32:44 +00:00
end
---
---@param filename string
---@param posX number -- X coordinate in world (virtual) pixels.
---@param posY number -- Y coordinate in world (virtual) pixels.
2022-08-07 20:31:09 +00:00
function EntityAPI . LoadCameraBound ( filename , posX , posY ) -- TODO: Change to use Vec2 object
2022-07-17 23:32:44 +00:00
return EntityLoadCameraBound ( filename , posX , posY )
end
2022-07-19 16:26:34 +00:00
---Creates a new entity from the given XML file, and attaches it to entity.
---This will not load tags and other stuff, it seems.
2022-07-17 23:32:44 +00:00
---@param filename string
---@param entity NoitaEntity
function EntityAPI . LoadToEntity ( filename , entity )
2022-07-19 16:26:34 +00:00
return EntityLoadToEntity ( filename , entity.ID )
2022-07-17 23:32:44 +00:00
end
---
---Note: works only in dev builds.
---@param filename string
function NoitaEntity : Save ( filename )
return EntitySave ( self.ID , filename )
end
---
---@param name string
---@return NoitaEntity|nil
function EntityAPI . CreateNew ( name )
2022-07-26 14:33:29 +00:00
return EntityAPI.Wrap ( EntityCreateNew ( name ) )
2022-07-17 23:32:44 +00:00
end
---
function NoitaEntity : Kill ( )
return EntityKill ( self.ID )
end
---
function NoitaEntity : IsAlive ( )
return EntityGetIsAlive ( self.ID )
end
---
---@param componentTypeName string
2022-07-23 15:45:06 +00:00
---@param tableOfComponentValues string[]
2022-07-17 23:32:44 +00:00
---@return NoitaComponent|nil
function NoitaEntity : AddComponent ( componentTypeName , tableOfComponentValues )
local componentID = EntityAddComponent ( self.ID , componentTypeName , tableOfComponentValues )
2022-07-26 14:33:29 +00:00
return ComponentAPI.Wrap ( componentID )
2022-07-17 23:32:44 +00:00
end
---
---@param component NoitaComponent
function NoitaEntity : RemoveComponent ( component )
return EntityRemoveComponent ( self.ID , component.ID )
end
---Returns a table of with all components of this entity.
---@return NoitaComponent[]
function NoitaEntity : GetAllComponents ( )
local componentIDs = EntityGetAllComponents ( self.ID ) or { }
local result = { }
for _ , componentID in ipairs ( componentIDs ) do
2022-07-26 14:33:29 +00:00
table.insert ( result , ComponentAPI.Wrap ( componentID ) )
2022-07-17 23:32:44 +00:00
end
return result
end
---Returns a table of components filtered by the given parameters.
---@param componentTypeName string
2022-07-18 20:07:53 +00:00
---@param tag string|nil
2022-07-17 23:32:44 +00:00
---@return NoitaComponent[]
function NoitaEntity : GetComponents ( componentTypeName , tag )
2022-07-18 20:07:53 +00:00
local componentIDs
if tag ~= nil then
componentIDs = EntityGetComponent ( self.ID , componentTypeName , tag ) or { }
else
componentIDs = EntityGetComponent ( self.ID , componentTypeName ) or { }
end
2022-07-17 23:32:44 +00:00
local result = { }
for _ , componentID in ipairs ( componentIDs ) do
2022-07-26 14:33:29 +00:00
table.insert ( result , ComponentAPI.Wrap ( componentID ) )
2022-07-17 23:32:44 +00:00
end
return result
end
---Returns the first component of this entity that fits the given parameters.
---@param componentTypeName string
2022-07-18 20:07:53 +00:00
---@param tag string|nil
2022-07-17 23:32:44 +00:00
---@return NoitaComponent|nil
function NoitaEntity : GetFirstComponent ( componentTypeName , tag )
2022-07-18 20:07:53 +00:00
local componentID
if tag ~= nil then
componentID = EntityGetFirstComponent ( self.ID , componentTypeName , tag )
else
componentID = EntityGetFirstComponent ( self.ID , componentTypeName )
end
2022-07-26 14:33:29 +00:00
return ComponentAPI.Wrap ( componentID )
2022-07-17 23:32:44 +00:00
end
---Sets the transform of the entity.
---@param x number
---@param y number
---@param rotation number
---@param scaleX number
---@param scaleY number
2022-08-07 20:31:09 +00:00
function NoitaEntity : SetTransform ( x , y , rotation , scaleX , scaleY ) -- TODO: Change to use Vec2 object
2022-07-17 23:32:44 +00:00
return EntitySetTransform ( self.ID , x , y , rotation , scaleX , scaleY )
end
---Sets the transform and tries to immediately refresh components that calculate values based on an entity's transform.
---@param x number
---@param y number
---@param rotation number
---@param scaleX number
---@param scaleY number
2022-08-07 20:31:09 +00:00
function NoitaEntity : SetAndApplyTransform ( x , y , rotation , scaleX , scaleY ) -- TODO: Change to use Vec2 object
2022-07-17 23:32:44 +00:00
return EntityApplyTransform ( self.ID , x , y , rotation , scaleX , scaleY )
end
---Returns the transformation of the entity.
---@return number x, number y, number rotation, number scaleX, number scaleY
2022-08-07 20:31:09 +00:00
function NoitaEntity : GetTransform ( ) -- TODO: Change to use Vec2 object
2022-07-17 23:32:44 +00:00
return EntityGetTransform ( self.ID )
end
---
---@param child NoitaEntity
function NoitaEntity : AddChild ( child )
return EntityAddChild ( self.ID , child.ID )
end
---
---@return NoitaEntity[]
function NoitaEntity : GetAllChildren ( )
local entityIDs = EntityGetAllChildren ( self.ID ) or { }
local result = { }
for _ , entityID in ipairs ( entityIDs ) do
2022-07-26 14:33:29 +00:00
table.insert ( result , EntityAPI.Wrap ( entityID ) )
2022-07-17 23:32:44 +00:00
end
return result
end
---
---@return NoitaEntity|nil
function NoitaEntity : GetParent ( )
2022-07-26 14:33:29 +00:00
return EntityAPI.Wrap ( EntityGetParent ( self.ID ) )
2022-07-17 23:32:44 +00:00
end
---Returns the given entity if it has no parent, otherwise walks up the parent hierarchy to the topmost parent and returns it.
2022-07-22 19:31:40 +00:00
---@return NoitaEntity|nil
2022-07-17 23:32:44 +00:00
function NoitaEntity : GetRootEntity ( )
2022-07-26 14:33:29 +00:00
return EntityAPI.Wrap ( EntityGetRootEntity ( self.ID ) )
2022-07-17 23:32:44 +00:00
end
---
function NoitaEntity : RemoveFromParent ( )
return EntityRemoveFromParent ( self.ID )
end
---
---@param tag string
---@param enabled boolean
function NoitaEntity : SetComponentsWithTagEnabled ( tag , enabled )
return EntitySetComponentsWithTagEnabled ( self.ID , tag , enabled )
end
---
---@param component NoitaComponent
---@param enabled boolean
function NoitaEntity : SetComponentsEnabled ( component , enabled )
return EntitySetComponentIsEnabled ( self.ID , component.ID , enabled )
end
---
---@return string
function NoitaEntity : GetName ( )
return EntityGetName ( self.ID )
end
---
---@param name string
function NoitaEntity : SetName ( name )
return EntitySetName ( self.ID , name )
end
---Returns an array of all the entity's tags.
---@return string[]
function NoitaEntity : GetTags ( )
---@type string
2022-07-23 15:45:06 +00:00
local tagsString = EntityGetTags ( self.ID ) or " "
2022-07-17 23:32:44 +00:00
local result = { }
for tag in tagsString : gmatch ( ' ([^,]+) ' ) do
table.insert ( result , tag )
end
return result
end
---Returns all entities with 'tag'.
---@param tag string
---@return NoitaEntity[]
function EntityAPI . GetWithTag ( tag )
local entityIDs = EntityGetWithTag ( tag ) or { }
local result = { }
for _ , entityID in ipairs ( entityIDs ) do
2022-07-26 14:33:29 +00:00
table.insert ( result , EntityAPI.Wrap ( entityID ) )
2022-07-17 23:32:44 +00:00
end
return result
end
---Returns all entities in 'radius' distance from 'x','y'.
---@param posX number -- X coordinate in world (virtual) pixels.
---@param posY number -- X coordinate in world (virtual) pixels.
---@param radius number -- Radius in world (virtual) pixels.
---@return NoitaEntity[]
2022-08-07 20:31:09 +00:00
function EntityAPI . GetInRadius ( posX , posY , radius ) -- TODO: Change to use Vec2 object
2022-07-17 23:32:44 +00:00
local entityIDs = EntityGetInRadius ( posX , posY , radius ) or { }
local result = { }
for _ , entityID in ipairs ( entityIDs ) do
2022-07-26 14:33:29 +00:00
table.insert ( result , EntityAPI.Wrap ( entityID ) )
2022-07-17 23:32:44 +00:00
end
return result
end
---Returns all entities in 'radius' distance from 'x','y' that have the given tag.
---@param posX number -- X coordinate in world (virtual) pixels.
---@param posY number -- X coordinate in world (virtual) pixels.
---@param radius number -- Radius in world (virtual) pixels.
---@param tag string
---@return NoitaEntity[]
2022-08-07 20:31:09 +00:00
function EntityAPI . GetInRadiusWithTag ( posX , posY , radius , tag ) -- TODO: Change to use Vec2 object
2022-07-17 23:32:44 +00:00
local entityIDs = EntityGetInRadiusWithTag ( posX , posY , radius , tag ) or { }
local result = { }
for _ , entityID in ipairs ( entityIDs ) do
2022-07-26 14:33:29 +00:00
table.insert ( result , EntityAPI.Wrap ( entityID ) )
2022-07-17 23:32:44 +00:00
end
return result
end
---
---@param posX number -- X coordinate in world (virtual) pixels.
---@param posY number -- X coordinate in world (virtual) pixels.
---@return NoitaEntity|nil
2022-08-07 20:31:09 +00:00
function EntityAPI . GetClosest ( posX , posY ) -- TODO: Change to use Vec2 object
2022-07-26 14:33:29 +00:00
return EntityAPI.Wrap ( EntityGetClosest ( posX , posY ) )
2022-07-17 23:32:44 +00:00
end
---
---@param name string
---@return NoitaEntity|nil
function EntityAPI . GetWithName ( name )
2022-07-26 14:33:29 +00:00
return EntityAPI.Wrap ( EntityGetWithName ( name ) )
2022-07-17 23:32:44 +00:00
end
---
---@param tag string
function NoitaEntity : AddTag ( tag )
return EntityAddTag ( self.ID , tag )
end
---
---@param tag string
function NoitaEntity : RemoveTag ( tag )
return EntityRemoveTag ( self.ID , tag )
end
---
---@param tag string
---@return boolean
function NoitaEntity : HasTag ( tag )
return EntityHasTag ( self.ID , tag )
end
---
---@return string -- example: 'data/entities/items/flute.xml'.
function NoitaEntity : GetFilename ( )
return EntityGetFilename ( self.ID )
end
---Creates a component of type 'component_type_name' and adds it to 'entity_id'.
---'table_of_component_values' should be a string-indexed table, where keys are field names and values are field values of correct type.
---The value setting works like ComponentObjectSetValue2(), with the exception that multivalue types are not supported.
---Additional supported values are _tags:comma_separated_string and _enabled:bool, which basically work like the those fields work in entity XML files.
---Returns the created component, if creation succeeded, or nil.
---@param componentTypeName string
---@param tableOfComponentValues table<string, any>
---@return NoitaComponent|nil
function NoitaEntity : EntityAddComponent ( componentTypeName , tableOfComponentValues )
local componentID = EntityAddComponent2 ( self.ID , componentTypeName , tableOfComponentValues )
2022-07-26 14:33:29 +00:00
return ComponentAPI.Wrap ( componentID )
2022-07-17 23:32:44 +00:00
end
-- TODO: Add missing Noita API methods and functions.
2022-08-07 20:31:09 +00:00
---
---@return NoitaEntity|nil
function EntityAPI . GetUpdatedEntity ( )
return EntityAPI.Wrap ( GetUpdatedEntityID ( ) )
end
---
---@return NoitaEntity|nil
function EntityAPI . GetWorldStateEntity ( )
return EntityAPI.Wrap ( GameGetWorldStateEntity ( ) )
end
---
---@return NoitaEntity|nil
function EntityAPI . GetPlayerStatsEntity ( )
return EntityAPI.Wrap ( GameGetPlayerStatsEntity ( ) )
end
-- TODO: Add missing Noita API methods and functions.
---
function NoitaEntity : RegenItemAction ( )
return GameRegenItemAction ( self.ID )
end
---
function NoitaEntity : RegenItemActionsInContainer ( )
return GameRegenItemActionsInContainer ( self.ID )
end
---
function NoitaEntity : RegenItemActionsInPlayer ( )
return GameRegenItemActionsInPlayer ( self.ID )
end
---
---@param itemEntity NoitaEntity
function NoitaEntity : KillInventoryItem ( itemEntity )
return GameKillInventoryItem ( self.ID , itemEntity.ID )
end
---
---@param itemEntity NoitaEntity
---@param doPickUpEffects boolean
function NoitaEntity : PickUpInventoryItem ( itemEntity , doPickUpEffects )
if doPickUpEffects == nil then doPickUpEffects = true end
return GamePickUpInventoryItem ( self.ID , itemEntity.ID , doPickUpEffects )
end
---
function NoitaEntity : DropAllItems ( )
return GameDropAllItems ( self.ID )
end
---
function NoitaEntity : DropPlayerInventoryItems ( )
return GameDropPlayerInventoryItems ( self.ID )
end
---
function NoitaEntity : DestroyInventoryItems ( )
return GameDestroyInventoryItems ( self.ID )
end
-- TODO: Add missing Noita API methods and functions.
2022-07-28 10:38:26 +00:00
---
---@return boolean
function NoitaEntity : IsPlayer ( )
return IsPlayer ( self.ID )
end
---
---@return boolean
function NoitaEntity : IsInvisible ( )
return IsInvisible ( self.ID )
end
-- TODO: Add missing Noita API methods and functions.
2022-07-22 19:31:40 +00:00
-------------------------
-- JSON Implementation --
-------------------------
2022-07-22 17:10:15 +00:00
2022-07-22 19:31:40 +00:00
---MarshalJSON implements the JSON marshaler interface.
---@return string
function NoitaEntity : MarshalJSON ( )
local result = {
name = self : GetName ( ) ,
filename = self : GetFilename ( ) ,
tags = self : GetTags ( ) ,
children = self : GetAllChildren ( ) ,
components = self : GetAllComponents ( ) ,
transform = { } ,
}
2022-07-22 17:10:15 +00:00
2022-07-22 19:31:40 +00:00
result.transform . x , result.transform . y , result.transform . rotation , result.transform . scaleX , result.transform . scaleY = self : GetTransform ( )
2022-07-22 17:10:15 +00:00
2022-07-23 08:57:25 +00:00
return JSON.Marshal ( result )
2022-07-22 17:10:15 +00:00
end
2022-07-22 19:31:40 +00:00
return EntityAPI