Mod: 实用脚本

此页面的内容需要被翻译。

你可以帮助我们来翻译此页面。

模组页面

A collection of scripts created by other modders, which you can copy directly to your own mod, for example into your own utilities file: `mods/<MY_MOD>/files/scripts/utilities.lua`

## Obtain the id of the player entity

This function obtains you the id of the player entity. Using it, you can extract data from components and other behaviors of the player.

```
-- simple utility function to return the player entity
function getPlayerEntity()
	local players = EntityGetWithTag("player\_unit")
	if #players == 0 then return end

	return players[1]
end

```

## Easier entity debugging

```
function str(var)
  if type(var) == 'table' then
    local s = '{ '
    for k,v in pairs(var) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. str(v) .. ','
    end
    return s .. '} '
  end
  return tostring(var)
end

function debug\_entity(e)
    local parent = EntityGetParent(e)
    local children = EntityGetAllChildren(e)
    local comps = EntityGetAllComponents(e)

    print("--- ENTITY DATA ---")
    print("Parent: ["..parent.."] " .. (EntityGetName(parent) or "nil"))

    print(" Entity: ["..str(e).."] " .. (EntityGetName(e) or "nil"))
    print(" Tags: " .. (EntityGetTags(e) or "nil"))
    if (comps ~= nil) then
      for \_, comp in ipairs(comps) do
          print(" Comp: ["..comp.."] " .. (ComponentGetTypeName(comp) or "nil"))
      end
    end

    if children == nil then return end

    for \_, child in ipairs(children) do
        local comps = EntityGetAllComponents(child)
        print(" Child: ["..child.."] " .. EntityGetName(child))
        for \_, comp in ipairs(comps) do
            print(" Comp: ["..comp.."] " .. (ComponentGetTypeName(comp) or "nil"))
        end
    end
    print("--- END ENTITY DATA ---")
end

```
Use simply with `debug_entity(entity)`

## Add custom names in translations

This piece of code is placed in the mod's init and is used to add custom translations:

```
local content = ModTextFileGetContent("data/translations/common.csv")
ModTextFileSetContent("data/translations/common.csv", content .. [[
item\_custom,Custom Name,,,,,,,,,,,,,
]])

```

So if we were to name the entity "$item\_custom" it's name in game would show up as "Custom Name"

## Add new genomes (compatible with other mods)

The function `add_new_genome` let's you append a new genome to the `data/genome_relations.csv` file. Use it in your `init.lua`.

(Keith and Horscht fixed this so now it finally works!)

```
function split\_string(inputstr, sep)
  sep = sep or "%s"
  local t= {}
  for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
    table.insert(t, str)
  end
  return t
end

local content = ModTextFileGetContent("data/genome\_relations.csv")

--The function works like this: genome\_name is the name of your new genome/faction,
--default\_relation\_ab is the relation with all the horizontal genomes which relations weren't specified in the table,
--default\_relation\_ba is the relation with all the vertical genomes which relations weren't specified in the table,
--self relation is the genome's relation with itself,
--relations is a table which directly specifies the value of the genome relation with.

function add\_new\_genome(content, genome\_name, default\_relation\_ab, default\_relation\_ba, self\_relation, relations)
  local lines = split\_string(content, "\r\n")
  local output = ""
  local genome\_order = {}
  for i, line in ipairs(lines) do
    if i == 1 then
      output = output .. line .. "," .. genome\_name .. "\r\n"
    else
      local herd = line:match("([%w\_-]+),")
      output = output .. line .. ","..(relations[herd] or default\_relation\_ba).."\r\n"
      table.insert(genome\_order, herd)
    end
  end

  local line = genome\_name
  for i, v in ipairs(genome\_order) do
    line = line .. "," .. (relations[v] or default\_relation\_ab)
  end
  output = output .. line .. "," .. self\_relation

  return output
end

-- Example usage: (This sets all genome relations of this genome to 100, unless indicated so, in this case, I want 100 with everything, except the player and -1)
content = add\_new\_genome(content, "genome1", 100, 100, 100, {
  player = 0,
  ["-1"] = 0
})
--Here I want 0 genome relations with everything, except for 100 with itself
content = add\_new\_genome(content, "genome2", 0, 0, 100, {})

ModTextFileSetContent("data/genome\_relations.csv", content)

```

## Add a new tag to an existing entity file

This function adds a tag to an existing entity without you having to overwrite existing entities:

```
function add\_tags()

	local xml2lua = dofile("mods/new\_enemies/files/xml2lua\_library/xml2lua.lua")
	local xml\_content = ModTextFileGetContent("data/entities/props/existing\_entity.xml")
	local handler = xml2lua.parse(xml\_content)
	if handler.root.Entity.\_attr.tags then
	  handler.root.Entity.\_attr.tags = handler.root.Entity.\_attr.tags .. ",your\_tag\_name"
	else
	  handler.root.Entity.\_attr.tags = "your\_tag\_name"
	end
	local xml\_output = xml2lua.toXml(handler.root, "Entity", 0)
	ModTextFileSetContent("data/entities/props/existing\_entity.xml", xml\_output)

end

add\_tags\_seamine()

```

## Rotate entity depending on topology of terrain

This script makes the entity rotate depending on terrain topology:

```
function approx\_rolling\_average(avg, new\_sample, n)
  avg = avg - avg / n;
  avg = avg + new\_sample / n;
  return avg
end

local old\_average = GetValueNumber("average\_rotation", 0)

function get\_direction( x1, y1, x2, y2 )
  return math.atan2( ( y2 - y1 ), ( x2 - x1 ) )
end

local entity\_id = GetUpdatedEntityID()
local x, y = EntityGetTransform(entity\_id)
local found\_normal, normal\_x, normal\_y, approximate\_distance\_from\_surface = GetSurfaceNormal(x, y, 60, 16)
local dir = get\_direction(0, 0, normal\_x, normal\_y)
local degree\_shift = math.rad(-90) + dir -- 90 degree rotation to properly orient the entity
local new\_average = approx\_rolling\_average(old\_average, degree\_shift, 5) -- if the number is higher than 5 the turning speed would be smoother and slower, if less it would be more instantaneous
SetValueNumber("average\_rotation", new\_average)

if found\_normal then
 EntitySetTransform(entity\_id, x, y, new\_average)
end

```

This script is then attached to the xml entity with a lua component, example:

```
 <LuaComponent
 \_enabled="1"
 script\_source\_file="mods/yourmod/files/the\_script\_above.lua"
 execute\_every\_n\_frame="1">
 </LuaComponent>

```

## Shoot Projectile from Entity Towards Player

This script, made by Evaisa, lets you shoot a projectile from an entity towards an entity.

```
dofile( "data/scripts/lib/utilities.lua" )

function rotate\_degrees(x, y, degrees)
	return rotate\_radians(x, y, math.rad(degrees))
end

function rotate\_radians(x, y, radians)
	local ca = math.cos(radians)
	local sa = math.sin(radians)
	local out\_x = ca \* x - sa \* y
	local out\_y = sa \* x + ca \* y
	return out\_x, out\_y
end

function shoot\_at\_entity(self\_entity, target\_entity, general\_offset, x\_offset, y\_offset, speed, projectile, maxdistance, max\_player\_distance, rotation\_offset)
	local rad\_offset = 0
	if(rotation\_offset ~= nil)then
		rad\_offset = rotation\_offset
	end
	local x, y = EntityGetTransform(self\_entity)

	if(target\_entity ~= nil)then
		local entityX, entityY = EntityGetTransform( target\_entity )

		local headingX = entityX - (x + x\_offset)
		local headingY = (entityY-5) - (y + y\_offset)

		local len = math.sqrt((headingX\*headingX) + (headingY\*headingY))

		local directionX = headingX / len
		local directionY = headingY / len

		local didHit, hitX, hitY = RaytraceSurfaces( x, y, entityX, entityY )

		local headingHitX = entityX - hitX
		local headingHitY = entityY - hitY

		local hitDistance = math.sqrt((headingHitX\*headingHitX) + (headingHitY\*headingHitY))

		local pos\_x, pos\_y, currentRotation = EntityGetTransform( self\_entity )

		if(directionX < 0)then
			EntitySetTransform(self\_entity,pos\_x,pos\_y,currentRotation,-1,1)
		else
			EntitySetTransform(self\_entity,pos\_x,pos\_y,currentRotation,1,1)
		end

		if(len < max\_player\_distance)then
			if(hitDistance < maxdistance)then

				directionX, directionY = rotate\_degrees(directionX, directionY, rad\_offset)

				local ourProjectile = shoot\_projectile( self\_entity, projectile, x + (directionX \* general\_offset) + x\_offset, y + (directionY \* general\_offset) + y\_offset, directionX \* speed, directionY \* speed )
				edit\_component( ourProjectile, "ProjectileComponent", function(comp,vars)
					vars.mWhoShot       = self\_entity
					vars.mShooterHerdId = "player"
				end)
			end
		end
	end
end

```

To use this function, just do

```
shoot\_at\_entity([Attacker Entity], [Target Entity], [Projectile offset towards target], [Projectile Start X offset], [Projectile Start Y offset], [Projectile speed], [Projectile xml], [Distance to sense through walls], [Distance to see target])

```

Then attach a lua component to the entity xml which utilizes this script and runs every x frames, example:

```
<LuaComponent
 script\_source\_file="mods/yourmod/files/previous\_script.lua"
 execute\_every\_n\_frame="100"
 >
</LuaComponent>

```

## Attach entities to verlet chains

```
dofile\_once("data/scripts/lib/utilities.lua")

local entity = GetUpdatedEntityID()

local \_, \_, day, hour, minute, second = GameGetDateAndTimeLocal()
SetRandomSeed(day + hour + second, minute + second + entity)

local verlet\_data = {point\_count = 0, positions = {}}

local x, y = EntityGetTransform(entity)

local verlet\_entities = {}
local verlet\_files = {}
local empty\_percentage = 0

component\_read( EntityGetFirstComponent( entity, "VerletPhysicsComponent" ), { positions = {} }, function(comp)

    verlet\_data.point\_count = (#comp.positions / 2)

    for i = 1, verlet\_data.point\_count, 4 do
        local point = {x = 0, y = 0}
        point.x, point.y = comp.positions[i], comp.positions[i + 1]
        table.insert(verlet\_data.positions, point)
    end
end)

function set\_verlet\_position(verlet, x, y)
    component\_readwrite( EntityGetFirstComponent( verlet, "VerletPhysicsComponent" ), { positions = {} }, function(comp)
        comp.positions[1] = x
        comp.positions[2] = y
    end)
end

function delimiter\_split(input, delimiter)
    local word\_table = {}
    for word in string.gmatch(input, '([^'..delimiter..']+)') do
        table.insert(word\_table, word)
    end
    return word\_table
end

function tablelength(T)
    local count = 0
    for \_ in pairs(T) do count = count + 1 end
    return count
end

local holder = nil

local variable\_storage = EntityGetComponent(entity, "VariableStorageComponent")

for k, v in pairs(variable\_storage)do
    local name = ComponentGetValue2(v, "name")

    if(name == "verlet\_entity")then
        table.insert(verlet\_entities, tonumber(ComponentGetValue2(v, "value\_string")))
    elseif(name == "verlet\_files")then
        verlet\_files = delimiter\_split(ComponentGetValue2(v, "value\_string"), ',')
    elseif(name == "holder")then
        holder = tonumber(ComponentGetValue2(v, "value\_string"))
    end
end

for k, position in pairs(verlet\_data.positions)do
    if(verlet\_entities[1] ~= nil)then
        if(verlet\_entities[k] ~= 0)then
            if(EntityGetIsAlive(verlet\_entities[k]))then
                EntitySetTransform(verlet\_entities[k], position.x, position.y)
                set\_verlet\_position(verlet\_entities[k], position.x, position.y)
            end
        end
    else
        if(0 == empty\_percentage)then

			-- for k, position in pairs(verlet\_data.positions)do
			    -- if k % 2 == 0 then
					local verlet\_file = verlet\_files[Random(1, #verlet\_files)]
					local verlet = EntityLoad(verlet\_file, x, y)
					EntityAddChild(entity, verlet)
					if(verlet ~= nil)then

						EntityAddComponent(entity, "VariableStorageComponent", {
							name="verlet\_entity",
							value\_string=tostring(verlet),
						})
					   -- GamePrint("holder = "..holder)
						if(holder ~= 0)then
							EntityAddComponent(holder, "VariableStorageComponent", {
								name="verlet\_entity",
								value\_string=tostring(verlet),
							})
						end

					end
				-- end
			-- end
        else
            EntityAddComponent(entity, "VariableStorageComponent", {
                name="verlet\_entity",
                value\_string="0",
            })
        end
    end
end

```

Add this to the verlet chain entity like this:

```
 <VariableStorageComponent
 name="verlet\_files"
 value\_string="mods/yourmod/files/entity\_you\_want\_to\_attach\_to\_verlet.xml"
 ></VariableStorageComponent>

 <LuaComponent
 \_enabled="1"
 script\_source\_file="mods/yourmod/files/the\_lua\_script\_above.lua"
 execute\_on\_added="1"
 execute\_every\_n\_frame="0">
 </LuaComponent>

```

This will add one entity to each verlet chain segment! Keep in mind that it is heavy on performance.

## Rotate physics object towards player

```
dofile\_once("data/scripts/lib/utilities.lua")

local this\_entity = GetUpdatedEntityID()

local x, y, r = EntityGetTransform(this\_entity)

local variable\_storage = EntityGetComponent(this\_entity, "VariableStorageComponent")

local aim\_direction = {x = 0, y = 0}

local players = EntityGetWithTag("player\_unit")

if #players > 0 then

	local player\_x, player\_y = EntityGetTransform(players[1])

	local direction\_x, direction\_y = player\_x - x, player\_y - y

	local len = math.sqrt((direction\_x\*direction\_x) + (direction\_y\*direction\_y))

	aim\_direction.x, aim\_direction.y = direction\_x / len, direction\_y / len

	local phys\_body = EntityGetFirstComponent(this\_entity, "PhysicsBodyComponent")

	local ang\_vel = PhysicsGetComponentAngularVelocity( this\_entity, phys\_body )

	function angle\_rad(direction)
		return math.atan2(direction.y,direction.x)
	end

	function get\_torque(current\_angle, target\_angle, speed)
		-- Make angle go from 0 to 2pi
		if target\_angle < 0 then
		  target\_angle = target\_angle + math.pi \* 2
		end
		if current\_angle < 0 then
		  current\_angle = current\_angle + math.pi \* 2
		end

		local dist\_up = math.abs(target\_angle - current\_angle)
		local dist\_down = math.abs((current\_angle + math.pi \* 2) - target\_angle)

		if current\_angle > target\_angle then
		  dist\_up = math.abs((target\_angle + math.pi \* 2) - current\_angle)
		  dist\_down = math.abs(current\_angle - target\_angle)
		end

		local dir
		if math.abs(dist\_up) < math.abs(dist\_down) then
		  dir = 1
		else
		  dir = -1
		end
		local dist\_smallest = dist\_up
		if dist\_down < dist\_up then
		  dist\_smallest = dist\_down
		end

		local new\_angle = speed \* dir

		return new\_angle
	end

	PhysicsApplyTorque( this\_entity, -ang\_vel )

	PhysicsApplyTorque( this\_entity, get\_torque(r, angle\_rad(aim\_direction), 5) )

end

```

This script is then attached to the xml entity with a lua component, example:

```
 <LuaComponent
 \_enabled="1"
 script\_source\_file="mods/yourmod/files/the\_script\_above.lua"
 execute\_every\_n\_frame="1">
 </LuaComponent>

```

For this to work it is important to remove any torque from the physics AI of the entity bearing the lua component by setting torque to 0 in the physics AI component.

```
<PhysicsAIComponent
 torque\_balancing\_coeff="0"
 torque\_coeff="0"
 torque\_max="0" >
</PhysicsAIComponent>

```

## Check if inside wall script

This function checks if you're spawning things in walls.

```
function is\_inside\_wall(x, y, radius)
  for i=1,8 do
    local slice = math.pi \* 2 / 8 \* i
    local did\_hit, hit\_x, hit\_y = RaytraceSurfacesAndLiquiform(x, y, x + math.cos(slice) \* radius, y + math.sin(slice) \* radius)
    if did\_hit then
      return true
    end
  end
  return false
end

if not is\_inside\_wall(x, y, 32) then
  -- Whatever you want to do!
end

```

## Player movement checking

Use these functions to obtain flags regarding the player's movement.

```
-- returns "right" if the player is moving right, "left" if the player is moving left, or an empty string if neither
function getPlayerHorizontalMovement()
	local vel\_x, vel\_y = getPlayerVelocities()
	local horizontal\_movement = ""
	if(vel\_x > 10) then
		horizontal\_movement = "right"
	end
	if(vel\_x < -10) then
		horizontal\_movement = "left"
	end
	return horizontal\_movement
end

-- returns "down" if the player is falling, "up" if the player is going up, or an empty string if neither
function getPlayerVerticalMovement()
	local vel\_x, vel\_y = getPlayerVelocities()
	local vertical\_movement = ""
	if(vel\_y > 0 and vel\_y ~= 60) then
		vertical\_movement = "down"
	end
	if(vel\_y < 0) then
		vertical\_movement = "up"
	end
	return vertical\_movement
end

-- returns true if the player is moving, or false otherwise
function isPlayerMoving()
    local flag = false
    local x, y = EntityGetTransform( getPlayerEntity() )

    local movement\_threshold = 0.1
    if old\_position and (math.abs(x - old\_position.x) > movement\_threshold or math.abs(y - old\_position.y) > movement\_threshold) then
        flag = true
    end
    old\_position = {x=x, y=y};

    return flag
end

-- returns true if the player is standing on solid ground, or false if in the air
function isPlayerStanding()
    local vel\_x, vel\_y = getPlayerVelocities()
    if(vel\_y == 60) then -- default gravity value when the player is standing on something solid
        return true
    else
        return false
    end
end

-- obtains x and y velocities from the player
function getPlayerVelocities()
    local cdc\_id = EntityGetFirstComponentIncludingDisabled(getPlayerEntity(), "CharacterDataComponent")
    local velocity\_x, velocity\_y = ComponentGetValue2(cdc\_id, "mVelocity")
    return velocity\_x, velocity\_y
end

```

## Obtaining and setting gold amount

These functions can be used to manipulate the amount of gold owned by the player.

```
-- function to add or subtract gold from player
-- amount can be either negative or positive
function addPlayerGold(amount)

	local player = getPlayerEntity()

	local wallet = EntityGetFirstComponent(player, "WalletComponent")
	local money = ComponentGetValueInt(wallet, "money")
	local player\_money = money + amount

	edit\_component(player, "WalletComponent", function(comp,vars)
		vars.money = player\_money
	end)
end

-- function to get player gold
function getPlayerGold()

	local player = getPlayerEntity()

	local wallet = EntityGetFirstComponent(player, "WalletComponent")
	local money = ComponentGetValueInt(wallet, "money")

	return money
end

```

## Internal variable manipulation

The following functions can be used to obtain or update internal variables present in a variable storage component of an entity. Both get and set functions assume the variable name you are trying to get or set already exists in the entity you are providing.

```
-- function to obtain a value from an internal variable contained in a variable storage component
-- entity\_id is the id of the entity whose internal variables will be accessed
-- variable\_name is the name of the internal variable to be accesses
-- variable\_type is type indicator of the internal variable, which can be value\_string, value\_int or value\_float
function getInternalVariableValue(entity\_id, variable\_name, variable\_type)
	local value = nil
	local components = EntityGetComponent( entity\_id, "VariableStorageComponent" )
	if ( components ~= nil ) then
		for key,comp\_id in pairs(components) do
			local var\_name = ComponentGetValue2( comp\_id, "name" )
			if(var\_name == variable\_name) then
				value = ComponentGetValue2(comp\_id, variable\_type)
			end
		end
	end
	return value
end

-- function to set a value of an internal variable contained in a variable storage component of an entity with entity\_id with name variable\_name and type variable\_type
-- entity\_id is the id of the entity whose internal variables will be accessed
-- variable\_name is the name of the internal variable to be accesses
-- variable\_type is type indicator of the internal variable, which can be value\_string, value\_int or value\_float
function setInternalVariableValue(entity\_id, variable\_name, variable\_type, new\_value)

	local components = EntityGetComponent( entity\_id, "VariableStorageComponent" )
	if ( components ~= nil ) then
		for key,comp\_id in pairs(components) do
			local var\_name = ComponentGetValue2( comp\_id, "name" )
			if( var\_name == variable\_name) then
				ComponentSetValue2( comp\_id, variable\_type, new\_value )
			end
		end
	end
end

-- function to add new internal variables to an entity
-- entity\_id is the id of the entity that will receive a new internal variable
-- variable\_type is the type of variable being added, can be value\_int, value\_string or value\_float
-- initial\_value is the starting value of the variable being added, if none, must be provided as, e.g., 0, "", or 0.0
function addNewInternalVariable(entity\_id, variable\_name, variable\_type, initial\_value)
	if(variable\_type == "value\_int") then
		EntityAddComponent2(entity\_id, "VariableStorageComponent", {
			name=variable\_name,
			value\_int=initial\_value
		})
	elseif(variable\_type == "value\_string") then
		EntityAddComponent2(entity\_id, "VariableStorageComponent", {
			name=variable\_name,
			value\_string=initial\_value
		})
	elseif(variable\_type == "value\_float") then
		EntityAddComponent2(entity\_id, "VariableStorageComponent", {
			name=variable\_name,
			value\_float=initial\_value
		})
	elseif(variable\_type == "value\_bool") then
		EntityAddComponent2(entity\_id, "VariableStorageComponent", {
			name=variable\_name,
			value\_bool=initial\_value
		})
	end
end

```

## Player Health manipulation

The following functions can be used to manipulate and obtain hp from the player.

```
-- function to return player health
-- health values are treated internally as floats, so if the player has 5 health, the internal value will be 0.008
function getPlayerHealth()
	local damagemodels = EntityGetComponent( getPlayerEntity(), "DamageModelComponent" )
	local health = 0
	if( damagemodels ~= nil ) then
		for i,v in ipairs(damagemodels) do

			health = tonumber( ComponentGetValue( v, "hp" ) )
			--GamePrint(health)
			break
		end
	end
	return health
end

-- function to return player max health
function getPlayerMaxHealth()
	local damagemodels = EntityGetComponent( getPlayerEntity(), "DamageModelComponent" )
	local maxHealth = 0
	if( damagemodels ~= nil ) then
		for i,v in ipairs(damagemodels) do

			maxHealth = tonumber( ComponentGetValue( v, "max\_hp" ) )

			break
		end
	end
	return maxHealth
end

-- function to add to player health
-- amount is how much is player health to be added to, may be positive or negative
-- amount must be provided as an integer
-- overheal\_flag tells the function if amount can update maximum health when amount added goes beyond it
function addPlayerHealth(amount, overheal\_flag)

	local damagemodels = EntityGetComponent( getPlayerEntity(), "DamageModelComponent" )

	if( damagemodels ~= nil ) then
		for i,v in ipairs(damagemodels) do

			currentHealth = tonumber( ComponentGetValue( v, "hp" ) )
			currentMaxHealth = tonumber( ComponentGetValue( v, "max\_hp") )

			local trueAmount = amount \* 0.04 -- how health scaling works when shown by UI
			local updatedHealth = currentHealth + trueAmount
			local updatedMaxHealth = 0

			local updatedHealth = currentHealth + trueAmount
			if(updatedHealth > currentMaxHealth and overheal\_flag) then -- overhealing, if new health goes beyond max health, max health is updated
				updatedMaxHealth = updatedHealth
				ComponentSetValue( v, "max\_hp", updatedMaxHealth)
				ComponentSetValue( v, "hp", updatedHealth)
			else
				if(updatedHealth <= 0) then
					updatedHealth = 0.04
				end
				ComponentSetValue( v, "hp", updatedHealth) -- sets health to 1 when updatedHealth is zero or below
			end

			break
		end
	end
end

-- function to directly set a value to player health
-- newHealth is the new health the player is going to have
-- newHealth must be provided as a float value
function setPlayerHealth(newHealth)
	local damagemodels = EntityGetComponent( getPlayerEntity(), "DamageModelComponent" )

	if( damagemodels ~= nil ) then
		for i,v in ipairs(damagemodels) do
			ComponentSetValue( v, "hp", newHealth)
		end
	end
end

```

## Get and set basic damage multipliers

The functions below are useful to obtain and modify damage multipliers of any creature with a valid id.

```
-- get all basic damage multipliers from entity with entity\_id
function getBasicDamageMultipliers(entity\_id)
	local dmc\_id = EntityGetFirstComponentIncludingDisabled(entity\_id, "DamageModelComponent")

	local ice = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "ice" )
	local fire = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "fire" )
	local drill = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "drill" )
	local slice = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "slice" )
	local melee = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "melee" )
	local projectile = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "projectile" )
	local radioactive = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "radioactive" )
	local explosion = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "explosion" )
	local electricity = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", "electricity" )

	return ice, fire, drill, slice, melee, projectile, radioactive, explosion, electricity
end

-- gets the value for a damage multiplier of an entity with entity\_id
-- multiplier\_name must be either ice, fire, drill, slice, melee, projectile, radioactive, explosion or electricity
function getBasicDamageMultiplier(entity\_id, multiplier\_name)
	local dmc\_id = EntityGetFirstComponentIncludingDisabled(entity\_id, "DamageModelComponent")
	local multiplier = ComponentObjectGetValue2( dmc\_id, "damage\_multipliers", multiplier\_name )
	return multiplier
end

-- sets a new value for a damage multiplier of an entity with entity\_id
-- multiplier\_name must be either ice, fire, drill, slice, melee, projectile, radioactive, explosion or electricity
function setBasicDamageMultiplier(entity\_id, multiplier\_name, new\_multiplier)
	local dmc\_id = EntityGetFirstComponentIncludingDisabled(entity\_id, "DamageModelComponent")

	ComponentObjectSetValue2( dmc\_id, "damage\_multipliers", multiplier\_name, new\_multiplier )
end

```

## Verlet Carrion Legs Script - by Horscht

This script gives your entity verlet tentacles which attach to walls like in the game Carrion.

```
dofile\_once("data/scripts/lib/utilities.lua")

------- CONFIG------
local num\_limbs = 5
local angle\_spread = 220
local cast\_length = 200
local move\_speed = 5
## local resting\_length = 20

local entity\_id = GetUpdatedEntityID()
local x, y = EntityGetTransform(entity\_id)
local last\_x = GetValueNumber("last\_x", x)
local last\_y = GetValueNumber("last\_y", y)
local vx, vy = x - last\_x, y - last\_y
local last\_direction = GetValueNumber("last\_direction", 0)
local direction = math.atan2(vy, vx)
if math.abs(vx) + math.abs(vy) > 0.1 then
  direction = rot\_lerp(direction, last\_direction, 0.05)
else
  direction = last\_direction
end
SetValueNumber("last\_direction", direction)
SetValueNumber("last\_x", x)
SetValueNumber("last\_y", y)
SetRandomSeed(x + entity\_id, y)

if not GetValueBool("initialized", false) then
  SetValueBool("initialized", true)
  for i=1, num\_limbs do
    local ent = EntityLoad("data/entities/verlet\_chains/vines/verlet\_vine\_pixelscene.xml")
    EntityAddComponent2(ent, "VerletWorldJointComponent")
    EntitySetName(ent, "tentacle\_limb")
    SetValueNumber("jiggle\_speed\_"..tostring(i), Randomf(1, 3))
    EntityAddChild(entity\_id, ent)
  end
end

local i = 0
for \_, child in ipairs(EntityGetAllChildren(entity\_id)) do
  if EntityGetName(child) ~= "tentacle\_limb" then goto continue end
  i = i + 1
  -- The limb's current position
  local x2, y2 = GetValueNumber("x\_"..tostring(i), x), GetValueNumber("y\_"..tostring(i), y)
  -- The position it's currently moving towards
  local target\_x, target\_y = GetValueNumber("target\_x\_"..tostring(i), x), GetValueNumber("target\_y\_"..tostring(i), y)
  local anchor\_found = GetValueBool("anchor\_found\_"..tostring(i), false)
  local cast\_direction\_x, cast\_direction\_y = vec\_rotate(math.cos(direction), math.sin(direction), math.rad(-angle\_spread/2 + (i-1) \* angle\_spread / (num\_limbs-1)))
  local move\_x, move\_y = vec\_normalize(target\_x - x2, target\_y - y2)
  x2 = x2 + move\_x \* move\_speed
  y2 = y2 + move\_y \* move\_speed
  if math.abs(x2 - target\_x) < 5 then
    x2 = target\_x
  end
  if math.abs(y2 - target\_y) < 5 then
    y2 = target\_y
  end

  if not anchor\_found then
    SetValueNumber("target\_x\_"..tostring(i), x + cast\_direction\_x \* resting\_length)
    SetValueNumber("target\_y\_"..tostring(i), y + cast\_direction\_y \* resting\_length)
  end

  -- Only do the raytracing stuff every x frames because it's probably expensive
  if GameGetFrameNum() % 20 == 0 then
    -- Check if there's still a pixel to hold on to
    local pixel\_found = GetSurfaceNormal(target\_x, target\_y, 2, 16)
    if not pixel\_found then
      anchor\_found = false
    end
    -- target\_hit checks if there's an obstacle between the main body and target
    local target\_hit, target\_hit\_x, target\_hit\_y = RaytraceSurfaces(x, y, target\_x - cast\_direction\_x \* 2, target\_y - cast\_direction\_y \* 2)
    local distance\_to\_target = get\_distance(x, y, target\_x, target\_y)

    -- Check if anchor is still in sight and range
    if not anchor\_found or target\_hit or (anchor\_found and distance\_to\_target > cast\_length) then
      -- Lost sight of anchor or anchor too far away, look for new anchor
      local hit, hit\_x, hit\_y = RaytraceSurfaces(x, y, x + cast\_direction\_x \* cast\_length, y + cast\_direction\_y \* cast\_length)
      if hit then
        -- Found new anchor, set target to it
        SetValueNumber("target\_x\_"..tostring(i), hit\_x)
        SetValueNumber("target\_y\_"..tostring(i), hit\_y)
        SetValueBool("anchor\_found\_"..tostring(i), true)
      else
        SetValueBool("anchor\_found\_"..tostring(i), false)
      end
    end
  end

  SetValueNumber("x\_"..tostring(i), x2)
  SetValueNumber("y\_"..tostring(i), y2)

  local verlet\_component = EntityGetFirstComponentIncludingDisabled(child, "VerletPhysicsComponent")
  local verlet\_world\_joint\_component = EntityGetFirstComponentIncludingDisabled(child, "VerletWorldJointComponent")
  local positions = ComponentGetValue2(verlet\_component, "positions")
  local add\_wave = anchor\_found and 0 or 3
  local jiggle\_speed = GetValueNumber("jiggle\_speed\_"..tostring(i), 1)
  positions[27] = x2 + math.cos(GameGetFrameNum() \* 0.02 + jiggle\_speed) \* add\_wave
  positions[28] = y2 + math.sin(GameGetFrameNum() \* 0.05 + jiggle\_speed) \* add\_wave
  ComponentSetValue2(verlet\_component, "positions", positions)
  -- world\_position is the origin of the verlet
  ComponentSetValue2(verlet\_world\_joint\_component, "world\_position", x, y)
  ::continue::
end

```

You just put this script in a lua component on the entity you want to have the tentacles like this:

```
 <LuaComponent
 script\_source\_file="mods/your\_mod/files/scripts/this\_script.lua"
 execute\_on\_added="1"
 execute\_every\_n\_frame="1"
 >
 </LuaComponent>

```

## Find if the player is polymorphed - by Soler91

This returns both a bool and the player entity if the player is indeed polymorphed; otherwise it returns nil.

```
function IsPlayerPolymorphed() -- returns bool, entityId/nil
    local polymorphed\_entities = EntityGetWithTag("polymorphed")
    if (polymorphed\_entities ~= nil) then
        for \_, entity\_id in ipairs(polymorphed\_entities) do
            local is\_player = false
            local game\_stats\_comp = EntityGetFirstComponent(entity\_id, "GameStatsComponent")
            if (game\_stats\_comp ~= nil) then
                is\_player = ComponentGetValue2(game\_stats\_comp, "is\_player")
            end
            if (is\_player) then
                return true, entity\_id
            end
        end
        return false, nil
    end
end

```

## Modify XML files

To modify XML files, it's best to use Zatherz' XML parser library: https://github.com/zatherz/luanxml

First, you get the contents of the XML you want to modify using `ModTextFileGetContent`, then you parse that using the XML parser, modify it (check the Github page for documentation on that) and write it back using `ModTextFileSetContent`, to convert the NXML object back to a string for saving, use `tostring()`.

Keep in mind that the `ModTextFileGet/SetContent` functions only exist in `init.lua` and disappear after `OnMagicNumbersAndWorldSeedInitialized` has run, so you need to do this before that. For instance simply outside any function, at the global level in `init.lua`

Here is some example code for how to change the EDR(Extremely Dense Rock)'s durability to 5 in the `data/materials.xml` file.

```
local nxml = dofile\_once("nxml.lua")
local content = ModTextFileGetContent("data/materials.xml")
local xml = nxml.parse(content)
for element in xml:each\_child() do
  if element.attr.name == "rock\_hard\_border" then
    element.attr.durability = 5
  end
end
ModTextFileSetContent("data/materials.xml", tostring(xml))

```

Or here's how to add a biome to `data/biome/_biomes_all.xml`:

```
local nxml = dofile\_once("nxml.lua")
local content = ModTextFileGetContent("data/biome/\_biomes\_all.xml")
local xml = nxml.parse(content)
xml:add\_child(nxml.parse([[
<Biome
  biome\_filename="mods/yourmod/files/biomes/your\_biome.xml"
  height\_index="0"
  color="ff123456">
</Biome>
]]))
ModTextFileSetContent("data/biome/\_biomes\_all.xml", tostring(xml))

```

## Constrain an entity to a set of coordinates - Thatrius

This pulls the effected entity back if it gets too far away. Works with physics objects.

```
function constrain(entity, x2, y2, max\_dist)
    local chardatacomp = EntityGetFirstComponent(entity, "CharacterDataComponent")
    local projcomp = EntityGetFirstComponent(entity, "VelocityComponent")
    local physcomp = EntityGetFirstComponent(entity, "PhysicsBodyComponent") or EntityGetFirstComponent(entity1, "PhysicsBody2Component") or EntityGetFirstComponent(entity1, "SimplePhysicsComponent")
    local vel\_x, vel\_y = ComponentGetValue2(chardatacomp, "mVelocity")
    local proj\_vel\_x, proj\_vel\_y = ComponentGetValue2(projcomp, "mVelocity")
    local x1, y1 = EntityGetTransform(entity)
    if (not x1) or (not x2) then return nil end

    local dist = math.sqrt(((x2-x1)^2) + ((y2-y1)^2))
    local target\_x = x2 + (((x1-x2)/dist)\*max\_dist)
    local target\_y = y2 + (((y1-y2)/dist)\*max\_dist)
    local target\_vel\_x = target\_x - x1
    local target\_vel\_y = target\_y - y1

    if dist > max\_dist then
        if physcomp or not proj\_vel\_x then
            PhysicsApplyForce(entity, target\_vel\_x\*100, target\_vel\_y\*100)
        end
        if vel\_x then
            vel\_y = vel\_y - 60
            local target\_mag = math.sqrt((target\_vel\_x^2) + (target\_vel\_y^2))
            local mag = math.sqrt((vel\_x^2) + (vel\_y^2)) / 40
            local force\_x = ((target\_vel\_x/target\_mag)\*mag)
            local force\_y = ((target\_vel\_y/target\_mag)\*mag)

            vel\_x = ((vel\_x + force\_x)\*1.025) + (target\_vel\_x\*dist\*0.8)
            vel\_y = ((vel\_y + force\_y)\*1.025) + (target\_vel\_y\*dist\*0.8)
            EntitySetTransform(entity, target\_x, target\_y)
            if ComponentGetValue2(chardatacomp, "is\_on\_ground") == false then vel\_x = vel\_x\*1.16 end
            ComponentSetValue2(chardatacomp, "mVelocity", vel\_x, vel\_y+60)
        elseif proj\_vel\_x then
            ComponentSetValue2(projcomp, "mVelocity", proj\_vel\_x+(target\_vel\_x\*100), proj\_vel\_y+(target\_vel\_y\*100))
            EntitySetTransform(entity, target\_x, target\_y)
        end
    end
end

```

To constrain two entities to each other, just run it on each of them using the other's coordinates:

```
x1, y1 = EntityGetTransform(entity1)
x2, y2 = EntityGetTransform(entity2)
constrain(entity1, x2, y2, 50)
constrain(entity2, x1, y1, 50)

```

## Inverse Kinematics script (works with more than 2 limb parts)

This glorious script was wrought into being by Thatrius:

## --Define Functions
function distance(x1,y1,x2,y2)
    return math.sqrt((x1 - x2)^2 + (y1 - y2)^2)
end

function approx\_rolling\_average(avg, target, n)
    avg = avg - avg / n;
    avg = avg + target / n;
    return avg
end
local smoothness\_factor = 6

## --General Setup
local entity = GetUpdatedEntityID()
local ex, ey = EntityGetTransform(entity)

local parent = EntityGetParent(entity)
local vel\_x, vel\_y = GameGetVelocityCompVelocity(parent)
local vel\_mag = math.sqrt((vel\_x)^2 + (vel\_y)^2)
local futurex, futurey = ex+(vel\_x\*60), ey+(vel\_y\*60)

local lengthcomp = EntityGetFirstComponent(entity, "VariableStorageComponent", "length")
local target = {GetValueNumber("targ\_x", ex), GetValueNumber("targ\_y", ey)}
local length = ComponentGetValue2(lengthcomp, "value\_int")
local time = GetValueNumber("time", 0)

## --Inverse Kinematics
--organize the segments and joints into neat little tables:
local legments = {} --"leg" + "segments"... haha funny word combo do you get
local joints = {}
local knees = {}
for i, child in ipairs(EntityGetAllChildren(entity)) do
    if not EntityHasTag(child, "knee") then
        local x, y = EntityGetTransform(child)
        if x == 0 then x = 1 end --safeguards against stupid "nan"s by making sure the code can never divide 0/0. Lost a piece of my soul in the frustration brought about by trying to track down a bug cause by this. Why does 0/0 have to equal "nan" in lua anyways and not just 0 or something, it serves no purpose except to create frustration, this is utterly retarted
        if y == 0 then y = 1 end
        table.insert(legments, child)
        if i == 1 then table.insert(joints, {ex, ey}) else table.insert(joints, {x, y}) end
    else
        table.insert(knees, child)
    end
end
table.insert(joints, target)

--First pass, starting at end of chain:
for i = #joints, 1, -1 do
    if i == #joints then
        --move joint directly to the target coords:
        joints[i] = target
    elseif i ~= 1 then
        --move joint within range of the previous one iterated:
        local jx, jy = joints[i][1], joints[i][2]
        local jx2, jy2 = joints[i+1][1], joints[i+1][2]
        if jx == jx2 or jy == jy2 then jx, jx = jx+1, jy+1 end --more nan-avoiding bullcrap
        local joint\_dist = distance(jx, jy, jx2, jy2)
        local jx = jx2 + (((jx-jx2) / joint\_dist) \* length)
        local jy = jy2 + (((jy-jy2) / joint\_dist) \* length)
        joints[i] = {jx, jy}
    end
end

--Second pass, starting at beginning of chain:
for i, joint in ipairs(joints) do
    if i ~= 1 then
        --move joint within range of the previous one iterated:
        local jx, jy = joints[i][1], joints[i][2]
        local jx2, jy2 = joints[i-1][1], joints[i-1][2]
        if jx == jx2 or jy == jy2 then jx, jx = jx+1, jy+1 end
        local joint\_dist = distance(jx, jy, jx2, jy2)
        local jx = jx2 + (((jx-jx2) / joint\_dist) \* length)
        local jy = jy2 + (((jy-jy2) / joint\_dist) \* length)
        joints[i] = {jx, jy}
    end
end

--Arrange all the legments to connect in between the joints:
for i, legment in ipairs(legments) do
    local jx, jy = math.floor(joints[i][1]), math.floor(joints[i][2])
    local jx2, jy2 = joints[i+1][1], joints[i+1][2]
    if jx == jx2 or jy == jy2 then jx, jx = jx+1, jy+1 end
    local vec\_x, vec\_y = jx2-jx, jy2-jy
    local targ\_rot = math.atan2(vec\_y, vec\_x)
    EntitySetTransform(legment, jx, jy, targ\_rot)
    if knees[i] then EntitySetTransform(knees[i], jx2, jy2) end
end

## --AI:
local total\_leglength = length\*#legments --combined length of all the segments in the leg
local length\_tolerance = total\_leglength--how far to let the end of the leg get before re-positioning it

--what the leg needs to point at:
local tx = GetValueNumber("tx", target[1])
local ty = GetValueNumber("ty", target[2])
local distance\_to\_target = distance(tx, ty, target[1], target[2])

--mix target position between ex, ey and tx, ty, based on time (picks up feet slightly when stepping):
local mult = smoothness\_factor \* (1+(2/3))
local inv = mult-time
local mix\_x = (ex/mult)\*time + (tx/mult)\*inv
local mix\_y = (ey/mult)\*time + (ty/mult)\*inv

--move feet toward target, unless already within range of it, in which case snap to the coordinates:
if distance\_to\_target > 10 then
    target[1] = approx\_rolling\_average(target[1], mix\_x, smoothness\_factor)
    target[2] = approx\_rolling\_average(target[2], mix\_y, smoothness\_factor)
elseif target[1] ~= tx and target[2] ~= ty then
    target[1] = tx
    target[2] = ty
    --[a stepping noise could go here]
end

--if the leg stretches too far, find a new target:
if (distance(tx, ty, ex, ey) > total\_leglength and distance(tx, ty, futurex, futurey) > total\_leglength) or distance(tx, ty, ex, ey) == 0 then
    local surfaces\_found = false
    --try to find nearby surfaces up to 3 times before resorting to stepping on air:
    for i=1,3 do
        potential\_x, potential\_y = (vel\_x\*60)+math.random(-total\_leglength, total\_leglength), (vel\_y\*60)+math.random(-total\_leglength, total\_leglength)
        mag = math.sqrt(((ex+potential\_x)-ex)^2 + ((ey+potential\_y)-ey)^2)
        potential\_x, potential\_y = ex + ((potential\_x/mag)\*total\_leglength), ey + ((potential\_y/mag)\*total\_leglength)
        did\_hit, hit\_x, hit\_y = RaytracePlatforms(ex, ey, potential\_x, potential\_y)
        if did\_hit then
            tx = hit\_x
            ty = hit\_y
            surfaces\_found = true
            break
        end
    end
    --step on air:
    if not surfaces\_found then
        tx = potential\_x
        ty = potential\_y
    end
    time = mult
end

--apply changes:
SetValueNumber("tx", tx)
SetValueNumber("ty", ty)
SetValueNumber("targ\_x", target[1])
SetValueNumber("targ\_y", target[2])
SetValueNumber("time", math.max(0,time-1))

```

To use it, name it "IK.lua" and put it in *mods/yourmod/files/.*

Then, save this xml script below as "ik\_leg.xml", and put it in *mods/yourmod/files/* as well*.*

```
 <Entity name="ik\_leg">

 <InheritTransformComponent>
 </InheritTransformComponent>

 <Entity tags="IK">
 <SpriteComponent
 image\_file="data/entities/animals/lukki/lukki\_feet/lukki\_limb\_a\_long.png"
 z\_index="1.1"
 offset\_x="0"
 offset\_y="5"
 >
 </SpriteComponent>
 </Entity>
 <Entity tags="knee">
 <SpriteComponent
 image\_file="data/entities/animals/lukki/lukki\_feet/lukki\_knee.png"
 z\_index="1.09"
 offset\_x="5"
 offset\_y="5"
 >
 </SpriteComponent>
 </Entity>
 <Entity tags="IK">
 <SpriteComponent
 image\_file="data/entities/animals/lukki/lukki\_feet/lukki\_limb\_a\_long.png"
 z\_index="1.1"
 offset\_x="0"
 offset\_y="5"
 >
 </SpriteComponent>
 </Entity>
 <Entity tags="knee">
 <SpriteComponent
 image\_file="data/entities/animals/lukki/lukki\_feet/lukki\_knee.png"
 z\_index="1.09"
 offset\_x="5"
 offset\_y="5"
 >
 </SpriteComponent>
 </Entity>
 <Entity tags="IK">
 <SpriteComponent
 image\_file="data/entities/animals/lukki/lukki\_feet/lukki\_limb\_b\_long.png"
 z\_index="1.1"
 offset\_x="0"
 offset\_y="5"
 >
 </SpriteComponent>
 </Entity>

 <LuaComponent
 script\_source\_file="yourmod/files/scripts/IK.lua"
 execute\_every\_n\_frame="1"
 remove\_after\_executed="0"
 >
 </LuaComponent>
 <VariableStorageComponent
 \_tags="length"
 value\_int="38"
 >
 </VariableStorageComponent>
 <VariableStorageComponent
 \_tags="IK\_targ\_x"
 value\_int="30"
 >
 </VariableStorageComponent>
 <VariableStorageComponent
 \_tags="IK\_targ\_y"
 value\_int="-60"
 >
 </VariableStorageComponent>
 </Entity>

```

By default this adds 3 limb segments to the leg. To add or remove segments, add or remove however many of these *</Entity>* child-block-things as you want (the parts of the xml that look like this):

```
 <Entity>
 <SpriteComponent
 image\_file="data/entities/animals/lukki/lukki\_feet/lukki\_limb\_a.png"
 z\_index="1.1"
 offset\_x="0"
 offset\_y="5"
 >
 </SpriteComponent>
 </Entity>

```

After you've saved the file, use Lua to spawn the *ik\_leg.xml* entity, and parent it to whichever other entity you want the IK leg to stick out of, like this:

```
local x, y = EntityGetTransform(entity)
local ik\_leg = EntityLoad("mods/yourmod/files/ik\_leg.xml", x, y)
EntityAddChild(entity, ik\_leg)

```

To set the coordinates you want the IK limb to point at, or to change the length between the joints, use Lua again to set *ik\_leg.xml*'s VariableStorageComponent values, like this:

```
local targcomp\_x = EntityGetFirstComponent(entity, "VariableStorageComponent", "IK\_targ\_x")
local targcomp\_y = EntityGetFirstComponent(entity, "VariableStorageComponent", "IK\_targ\_y")
local length\_between\_joints\_component = EntityGetFirstComponent(entity, "VariableStorageComponent", "length")

ComponentSetValue2(targcomp\_x, "value\_int", whatever\_number)
ComponentSetValue2(targcomp\_x, "value\_int", whatever\_number)
ComponentSetValue2(length\_between\_joints\_component, "value\_int", whatever\_number)

```

## Lua Wall: A Wall that works entirely through lua

This script gives you a wall through lua. It requires you to set the width and height of the wall, and then it does the rest.

As the script is built, the wall works only for the player character.

```
dofile\_once("data/scripts/lib/utilities.lua")

local entity\_id = GetUpdatedEntityID()
local x, y = EntityGetTransform(entity\_id)

local players = EntityGetWithTag("player\_unit")

local character\_data\_component = EntityGetFirstComponentIncludingDisabled(players[1], "CharacterDataComponent")
local vel\_x, vel\_y = ComponentGetValue2( character\_data\_component, "mVelocity" )
if #players > 0 then

    local player\_x, player\_y = EntityGetTransform(players[1])

	local old\_player\_x = GetValueNumber("old\_player\_x", player\_x)
	local old\_player\_y = GetValueNumber("old\_player\_y", player\_y)
	SetValueNumber("old\_player\_x", player\_x)
	SetValueNumber("old\_player\_y", player\_y)

    new\_x = player\_x
    new\_y = player\_y

	local variable\_storage = EntityGetComponent(entity\_id, "VariableStorageComponent")

	for k, v in pairs(variable\_storage)do
		local name = ComponentGetValue2(v, "name")

		if(name == "top\_edge")then
			top\_edge = ComponentGetValue2(v, "value\_string")
		elseif(name == "bottom\_edge")then
			bottom\_edge = ComponentGetValue2(v, "value\_string")
		elseif(name == "left\_edge")then
			left\_edge = ComponentGetValue2(v, "value\_string")
		elseif(name == "right\_edge")then
			right\_edge = ComponentGetValue2(v, "value\_string")
		end
	end

	local old\_top\_edge = GetValueNumber("old\_top\_edge", y)
	local old\_bottom\_edge = GetValueNumber("old\_bottom\_edge", y)
	SetValueNumber("old\_top\_edge", y + top\_edge)
	SetValueNumber("old\_bottom\_edge", y + bottom\_edge)

	local old\_left\_edge = GetValueNumber("old\_left\_edge", x)
	local old\_right\_edge = GetValueNumber("old\_right\_edge", x)
	SetValueNumber("old\_left\_edge", x + left\_edge)
	SetValueNumber("old\_right\_edge", x + right\_edge)

	if ( old\_player\_y < y + top\_edge or old\_player\_y > y + bottom\_edge ) or ( old\_top\_edge > player\_y ) or ( old\_bottom\_edge < player\_y ) then

		if ( player\_y > y + top\_edge and player\_y < y ) and ( player\_x > x + left\_edge and player\_x < x + right\_edge ) then

			new\_y = y + top\_edge - 1
			ComponentSetValue2(character\_data\_component, "is\_on\_ground", true)
			ComponentSetValue2(character\_data\_component, "mVelocity", vel\_x, 0)

		elseif ( player\_y < y + bottom\_edge and player\_y > y ) and ( player\_x > x + left\_edge and player\_x < x + right\_edge ) then

			new\_y = y + bottom\_edge + 2
			ComponentSetValue2(character\_data\_component, "mVelocity", vel\_x, 0)
		end

	-- elseif ( old\_player\_x < x + left\_edge or old\_player\_x > x + right\_edge ) or ( old\_left\_edge > player\_x ) or ( old\_right\_edge < player\_x ) then
	else

		if ( player\_x > x + left\_edge and player\_x < x ) and ( player\_y > y + top\_edge and player\_y < y + bottom\_edge ) then

			new\_x = x + left\_edge - 1

		elseif ( player\_x < x + right\_edge and player\_x > x ) and ( player\_y > y + top\_edge and player\_y < y + bottom\_edge ) then

			new\_x = x + right\_edge + 1

		end

	end

    if ( new\_x ~= player\_x ) or ( new\_y ~= player\_y ) then

        EntitySetTransform(players[1], new\_x, new\_y)

		--Inflict damage if squashing player:
		function kill\_player()

			EntityInflictDamage(players[1], 999, "DAMAGE\_PHYSICS\_HIT", "", "NORMAL", 0, 0)

			-- local damage\_model\_component = EntityGetFirstComponent(players[1], "DamageModelComponent")

			-- ComponentSetValue2(damage\_model\_component, "hp", 0)
			-- ComponentSetValue2(damage\_model\_component, "air\_needed", true)
			-- ComponentSetValue2(damage\_model\_component, "air\_in\_lungs", 0)

		end

		local ingrown\_factor = 1

		local player\_left\_width = ComponentGetValue2( character\_data\_component, "collision\_aabb\_min\_x" )
		local player\_right\_width = ComponentGetValue2( character\_data\_component, "collision\_aabb\_max\_x" )
		local player\_upper\_height = ComponentGetValue2( character\_data\_component, "collision\_aabb\_min\_y" ) - 1
		local player\_lower\_height = ComponentGetValue2( character\_data\_component, "collision\_aabb\_max\_y" )

		local check\_left\_edge, hit\_x1, hit\_y1 = RaytracePlatforms(player\_x + player\_left\_width, player\_y + player\_upper\_height + 1, player\_x + player\_left\_width, player\_y + player\_lower\_height - 1)
		local check\_right\_edge, hit\_x2, hit\_y2 = RaytracePlatforms(player\_x + player\_right\_width, player\_y + player\_upper\_height + 1, player\_x + player\_right\_width, player\_y + player\_lower\_height -1 )
		local check\_upper\_edge, hit\_x3, hit\_y3 = RaytracePlatforms(player\_x + player\_left\_width + 1, player\_y + player\_upper\_height, player\_x + player\_right\_width - 1, player\_y + player\_upper\_height )
		local check\_bottom\_edge, hit\_x4, hit\_y4 = RaytracePlatforms(player\_x + player\_left\_width + 1, player\_y + player\_lower\_height, player\_x + player\_right\_width - 1, player\_y + player\_lower\_height )

		--if ( ( old\_player\_x < x + left\_edge or old\_player\_x > x + right\_edge ) or ( old\_left\_edge > player\_x ) or ( old\_right\_edge < player\_x ) ) and ( check\_left\_edge or check\_right\_edge) then
		if ( ( old\_player\_x < x + left\_edge or old\_player\_x > x + right\_edge ) or ( old\_left\_edge > player\_x ) or ( old\_right\_edge < player\_x ) ) and ( check\_left\_edge or check\_right\_edge) then

			kill\_player()

		elseif ( ( old\_player\_y < y + top\_edge ) or ( old\_top\_edge > player\_y ) ) and check\_upper\_edge then
		-- elseif ( ( old\_player\_y < y + top\_edge or old\_player\_y > y + bottom\_edge ) or ( old\_top\_edge > player\_y ) or ( old\_bottom\_edge < player\_y ) ) and ( check\_upper\_edge or check\_bottom\_edge) then
			GamePrint("Squished Top")
			kill\_player()

		elseif ( ( old\_player\_y > y + bottom\_edge ) or ( old\_bottom\_edge < player\_y ) ) and check\_bottom\_edge then

			GamePrint("Squished Bottom")
			kill\_player()

		end

    end

end

```

Just run this every frame through a lua script on an entity and it will produce this malleable wall.

For this to work, the entity bearing the lua component needs to have a couple of variable storage components, defining the distance of edges from the center.

```
<Entity name="Lua Wall">

 <SpriteComponent
 image\_file="data/props\_gfx/temple\_door.png"
 offset\_x="7"
 offset\_y="30" >
 </SpriteComponent>

 <VariableStorageComponent
 name="top\_edge"
 value\_string="-30"
 ></VariableStorageComponent>

 <VariableStorageComponent
 name="bottom\_edge"
 value\_string="30"
 ></VariableStorageComponent>

 <VariableStorageComponent
 name="left\_edge"
 value\_string="-7"
 ></VariableStorageComponent>

 <VariableStorageComponent
 name="right\_edge"
 value\_string="7"
 ></VariableStorageComponent>

 <LuaComponent
 script\_source\_file="data/scripts/props/lua\_wall.lua"
 execute\_every\_n\_frame="1"
 >
 </LuaComponent>

</Entity>

```

## Storing values from a component and using them later

This tool will allow you to store values of a component in a variable storage component, make temporary changes to a component and then use insert the old values back later.

So first here's the lua script that stores the old values and sets the new values. In this case it's setting a bunch of values in the CharacterPlatformingComponent to 0.

```
dofile\_once("data/scripts/lib/utilities.lua")

local entity\_id    = GetUpdatedEntityID()

local character\_platforming\_component = EntityGetFirstComponentIncludingDisabled(entity\_id, "CharacterPlatformingComponent")

local properties\_to\_change = {
	run\_velocity = 0,
	fly\_speed\_max\_up = 0,
	jump\_velocity\_y = 0,
	jump\_velocity\_x = 0,
	fly\_velocity\_x = 0,
	fly\_speed\_max\_up = 0
}

if character\_platforming\_component then
	local old\_values = ""
	for k, v in pairs(properties\_to\_change) do
		local value = ComponentGetValue2(character\_platforming\_component, k)
		local string\_value = tostring(value)
		if type(value) == "boolean" then
			string\_value = value and "1" or "0"
		end
		old\_values = old\_values .. k .. ":" .. type(value) .. "=" .. string\_value
		if next(properties\_to\_change, k) then
			old\_values = old\_values .. ","
		end
		ComponentSetValue2(character\_platforming\_component, k, v)
	end

	EntityAddComponent2(entity\_id, "VariableStorageComponent", {
		name = "old\_values",
		value\_string = old\_values,
	})
end

```

Here's the script which would read out the old values from the variable storage component and which would set them back to what they were before on the entity:

```
dofile\_once("data/scripts/lib/utilities.lua")

function split\_string(inputstr, sep)
  sep = sep or "%s"
  local t= {}
  for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
    table.insert(t, str)
  end
  return t
end

function toboolean(str)
	return str == "1"
end

local entity\_id = GetUpdatedEntityID()
local character\_platforming\_component = EntityGetFirstComponentIncludingDisabled(entity\_id , "CharacterPlatformingComponent")
local var\_store = get\_variable\_storage\_component(entity\_id, "old\_values")
local stored\_values = ComponentGetValue2(var\_store, "value\_string")
if stored\_values then
	local properties = split\_string(stored\_values, ",")

	for i, v in ipairs(properties) do
		local name, prop\_type, value = string.match(v, "(.+):(.+)=(.+)")
		value = \_G["to"..prop\_type](value)
		ComponentSetValue2(character\_platforming\_component, name, value)
	end

	EntityRemoveComponent(entity\_id, var\_store)
end

```

And there you go. This will allow you to make temporary changes to a component for a temporary time, and then apply the old values back once you're done.

And that's about it, hopefully this all made sense, will update soon so it makes even *more* sense :D