preliminary investigation of special weapons axes and swords

This commit is contained in:
Tai Kedzierski 2018-12-27 18:48:37 +00:00
parent 7fc0c15025
commit 85fa36b08a
4 changed files with 143 additions and 136 deletions

View File

@ -5,22 +5,41 @@ local c_obsidian = minetest.get_content_id("default:obsidian")
local c_brick = minetest.get_content_id("default:obsidianbrick") local c_brick = minetest.get_content_id("default:obsidianbrick")
local c_chest = minetest.get_content_id("default:chest_locked") local c_chest = minetest.get_content_id("default:chest_locked")
nssm.lessvirulent = minetest.settings:get_bool("nssm.lessvirulent") local no_swap_nodes = {
nssm.safebones = minetest.settings:get_bool("nssm.safebones") "bones:bones",
nssm.cryosave = minetest.settings:get_bool("nssm.cryosave") "air",
"ignore",
"default:chest_locked",
}
function nssm:virulence(mobe) nssm.unswappable_node = function (pos, node_list)
if not nssm.lessvirulent then -- Return true if the original_node should not be swapped
return 0
local _, node, original_node
original_node = minetest.env:get_node(pos).name
if minetest.get_item_group(original_node) == "unbreakable" then
return true
end end
return math.ceil(100 / mobe.hp_max)
if minetest.is_protected(pos, "") then
return true
end
if node_list then
for _,node in pairs(node_list) do
if node == original_node then return true end
end
end
for _,node in pairs(no_swap_nodes) do
if node == original_node then return true end
end
return false
end end
function nssm:affectbones(mobe) -- as function for adaptable heuristic nssm.drops = function(drop)
return not nssm.safebones
end
function drops(drop)
if drop then if drop then
drop:setvelocity({ drop:setvelocity({
x = math.random(-10, 10) / 9, x = math.random(-10, 10) / 9,
@ -83,32 +102,6 @@ function dist_pos(p, s)
return r return r
end end
--check_for_death functions customized for monsters who respawns (Masticone)
function check_for_death_hydra(self)
local hp = self.object:get_hp()
if hp > 0 then
self.health = hp
if self.sounds.damage ~= nil then
minetest.sound_play(self.sounds.damage,{
object = self.object,
max_hear_distance = self.sounds.distance
})
end
return false
end
local pos = self.object:getpos()
local obj = nil
if self.sounds.death ~= nil then
minetest.sound_play(self.sounds.death,{
object = self.object,
max_hear_distance = self.sounds.distance
})
end
self.object:remove()
return true
end
function round(n) function round(n)
if (n>0) then if (n>0) then
return n % 1 >= 0.5 and math.ceil(n) or math.floor(n) return n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
@ -145,7 +138,6 @@ function digging_attack(
dim --vector representing the dimensions of the mob dim --vector representing the dimensions of the mob
) )
--if math.random(1,nssm:virulence(self)) ~= 1 then return end
if self.attack and self.attack:is_player() then if self.attack and self.attack:is_player() then
local s = self.object:getpos() local s = self.object:getpos()
local p = self.attack:getpos() local p = self.attack:getpos()
@ -155,53 +147,42 @@ function digging_attack(
local per = perpendicular_vector(dir) local per = perpendicular_vector(dir)
local posp = vector.add(s,dir) local posp = vector.add(s,dir)
--minetest.chat_send_all("La mia posizione:"..minetest.pos_to_string(s))
--minetest.chat_send_all("La posizione davanti:"..minetest.pos_to_string(posp))
posp = vector.subtract(posp,per) posp = vector.subtract(posp,per)
if nssm.unswappable_node(posp) then
return
end
local j
for j = 1,3 do for j = 1,3 do
--minetest.chat_send_all("pos1:"..minetest.pos_to_string(posp).." per.y= "..dim.y) local pos_to_dig = posp
if minetest.is_protected(posp, "") then
return
end
local pos1 = posp
for i = 0,dim.y do for i = 0,dim.y do -- from 0 to dy between mob and player altitude?
local target_node = minetest.env:get_node(pos_to_dig).name
--minetest.chat_send_all("pos2:"..minetest.pos_to_string(posp).." per.y= "..per.y) if not nssm.unswappable_node(pos_to_dig) then
minetest.remove_node(pos_to_dig)
local n = minetest.env:get_node(pos1).name
--local up = {x=pos.x+dx, y=pos.y+dy, z=pos.z+dz}
if group == nil then
if minetest.get_item_group(n, "unbreakable") == 1 or minetest.is_protected(pos1, "") or (n == "bones:bones" and not nssm:affectbones(self) ) then
else
--minetest.env:set_node(p, {name="air"})
minetest.remove_node(pos1)
end
else
if ((minetest.get_item_group(n, group)==1) and (minetest.get_item_group(n, "unbreakable") ~= 1) and (n ~= "bones:bones") and not (minetest.is_protected(pos1, "")) ) then
--minetest.env:set_node(p, {name="air"})
minetest.remove_node(pos1)
end
end end
pos1.y = pos1.y+1 pos_to_dig.y = pos_to_dig.y+1
end end
posp.y=s.y posp.y=s.y
posp=vector.add(posp,per) posp=vector.add(posp,per)
--minetest.chat_send_all("pos3:"..minetest.pos_to_string(posp).." per.y= "..per.y)
end end
end end
end end
local function safely_put_block(self, pos_under_mob, original_node, putting_block)
minetest.debug("Set node "..putting_block.." under "..minetest.pos_to_string(pos_under_mob))
if not nssm.unswappable_node(pos_under_mob, {putting_block}) then
minetest.env:set_node(pos_under_mob, {name = putting_block})
end
end
function putting_ability( --puts under the mob the block defined as 'p_block' function putting_ability( --sets 'putting_block' under the mob, as well as in front
self, --the entity of the mob self, -- the entity of the mob
p_block, --definition of the block to use putting_block, -- itemstring of block to put
max_vel --max velocity of the mob max_vel -- max velocity of the mob
) )
--if math.random(1,nssm:virulence(self)) ~= 1 then return end
local v = self.object:getvelocity() local v = self.object:getvelocity()
@ -222,31 +203,27 @@ function putting_ability( --puts under the mob the block defined as 'p_bl
end end
end end
local pos = self.object:getpos() local pos_under_mob = self.object:getpos()
local pos1 local pos_under_frontof_mob
pos.y=pos.y-1
pos1 = {x = pos.x+dx, y = pos.y, z = pos.z+dz}
local n = minetest.env:get_node(pos).name
local n1 = minetest.env:get_node(pos1).name
local oldmetainf = {minetest.get_meta(pos):to_table(),minetest.get_meta(pos1):to_table() }
if n~=p_block and not minetest.is_protected(pos, "") and (n == "bones:bones" and nssm:affectbones(self) ) and n~="air" then
minetest.env:set_node(pos, {name=p_block})
if nssm.cryosave then
local metai = minetest.get_meta(pos)
metai:from_table(oldmetainf[1]) -- this is enough to save the meta
metai:set_string("nssm",n)
end
end
if n1~=p_block and not minetest.is_protected(pos1, "") and (n == "bones:bones" and nssm:affectbones(self) ) and n~="air" then
minetest.env:set_node(pos1, {name=p_block})
if nssm.cryosave then
local metai = minetest.get_meta(pos1)
metai:from_table(oldmetainf[2]) -- this is enough to save the meta
metai:set_string("nssm",n1)
end
end
end
pos_under_mob.y=pos_under_mob.y - 1
pos_under_frontof_mob = {
x = pos_under_mob.x + dx,
y = pos_under_mob.y,
z = pos_under_mob.z + dz
}
local node_under_mob = minetest.env:get_node(pos_under_mob).name
local node_under_frontof_mob = minetest.env:get_node(pos_under_frontof_mob).name
local oldmetainf = {
minetest.get_meta(pos_under_mob):to_table(),
minetest.get_meta(pos_under_frontof_mob):to_table()
}
safely_put_block(self, pos_under_mob, node_under_mob, putting_block)
safely_put_block(self, pos_under_frontof_mob, node_under_frontof_mob, putting_block)
end
function webber_ability( --puts randomly around the block defined as w_block function webber_ability( --puts randomly around the block defined as w_block
self, --the entity of the mob self, --the entity of the mob
@ -254,8 +231,6 @@ function webber_ability( --puts randomly around the block defined as w_bl
radius --max distance the block can be put radius --max distance the block can be put
) )
if (nssm:virulence(self)~=0) and (math.random(1,nssm:virulence(self)) ~= 1) then return end
local pos = self.object:getpos() local pos = self.object:getpos()
if (math.random(1,55)==1) then if (math.random(1,55)==1) then
local dx=math.random(1,radius) local dx=math.random(1,radius)
@ -264,7 +239,7 @@ function webber_ability( --puts randomly around the block defined as w_bl
local t = {x=pos.x+dx, y=pos.y, z=pos.z+dz} local t = {x=pos.x+dx, y=pos.y, z=pos.z+dz}
local n = minetest.env:get_node(p).name local n = minetest.env:get_node(p).name
local k = minetest.env:get_node(t).name local k = minetest.env:get_node(t).name
if ((n~="air")and(k=="air")) and not minetest.is_protected(t, "") then if not unswappable_node(p) then
minetest.env:set_node(t, {name=w_block}) minetest.env:set_node(t, {name=w_block})
end end
end end
@ -278,15 +253,13 @@ function midas_ability( --ability to transform every blocks it touches in
height --height of the mob height --height of the mob
) )
if math.random(1,nssm:virulence(self)) ~= 1 then return end
local v = self.object:getvelocity() local v = self.object:getvelocity()
local pos = self.object:getpos() local pos = self.object:getpos()
--[[
if minetest.is_protected(pos, "") then if minetest.is_protected(pos, "") then
return return
end end
--]]
local max = 0 local max = 0
local yaw = (self.object:getyaw() + self.rotate) or 0 local yaw = (self.object:getyaw() + self.rotate) or 0
local x = math.sin(yaw)*-1 local x = math.sin(yaw)*-1
@ -317,8 +290,7 @@ function midas_ability( --ability to transform every blocks it touches in
local p = {x=pos.x+dx, y=pos.y+dy, z=pos.z+dz} local p = {x=pos.x+dx, y=pos.y+dy, z=pos.z+dz}
local n = minetest.env:get_node(p).name local n = minetest.env:get_node(p).name
if minetest.get_item_group(n, "unbreakable") == 1 or minetest.is_protected(p, "") or n=="air" or (n == "bones:bones" and not nssm:affectbones(self)) then if not unswappable_noed(p) then
else
minetest.env:set_node(p, {name=m_block}) minetest.env:set_node(p, {name=m_block})
end end
end end

View File

@ -598,6 +598,7 @@ minetest.register_tool("nssm:tarantula_warhammer", {
}) })
minetest.register_tool("nssm:axe_of_pride", { minetest.register_tool("nssm:axe_of_pride", {
-- Damage enemy, heal user by the same amount
description = "Axe of Pride", description = "Axe of Pride",
inventory_image = "axe_of_pride.png", inventory_image = "axe_of_pride.png",
wield_scale= {x=2,y=2,z=1.5}, wield_scale= {x=2,y=2,z=1.5},
@ -605,7 +606,7 @@ minetest.register_tool("nssm:axe_of_pride", {
full_punch_interval =1.3 , full_punch_interval =1.3 ,
max_drop_level=1, max_drop_level=1,
groupcaps={ groupcaps={
snappy={times={[1]=0.6, [2]=0.5, [3]=0.4}, uses=100, maxlevel=1}, choppy={times={[1]=0.6, [2]=0.5, [3]=0.4}, uses=100, maxlevel=1},
fleshy={times={[2]=0.8, [3]=0.4}, uses=400, maxlevel=1} fleshy={times={[2]=0.8, [3]=0.4}, uses=400, maxlevel=1}
}, },
damage_groups = {fleshy=16}, damage_groups = {fleshy=16},
@ -652,7 +653,10 @@ minetest.register_tool("nssm:axe_of_pride", {
if (obj:get_luaentity().health) then if (obj:get_luaentity().health) then
--minetest.chat_send_all("Entity") --minetest.chat_send_all("Entity")
obj:get_luaentity().health = obj:get_luaentity().health -10 obj:get_luaentity().health = obj:get_luaentity().health -10
check_for_death(obj:get_luaentity())
if obj:get_luaentity().check_for_death then
obj:get_luaentity():check_for_death({type = "punch"})
end
dropper:set_hp(dropper:get_hp()+10) dropper:set_hp(dropper:get_hp()+10)
--flag = 1 --flag = 1
@ -693,6 +697,7 @@ minetest.register_tool("nssm:axe_of_pride", {
}) })
minetest.register_tool("nssm:gratuitousness_battleaxe", { minetest.register_tool("nssm:gratuitousness_battleaxe", {
-- aka Battleaxe of Boom - causes and explosion at <epicenter_distance> nodes from player
description = "Gratuitousness Battleaxe", description = "Gratuitousness Battleaxe",
inventory_image = "gratuitousness_battleaxe.png", inventory_image = "gratuitousness_battleaxe.png",
wield_scale= {x=2.2,y=2.2,z=1.5}, wield_scale= {x=2.2,y=2.2,z=1.5},
@ -706,13 +711,14 @@ minetest.register_tool("nssm:gratuitousness_battleaxe", {
damage_groups = {fleshy=18}, damage_groups = {fleshy=18},
}, },
on_drop = function(itemstack, dropper, pos) on_drop = function(itemstack, dropper, pos)
local epicenter_distance = 10
local objects = minetest.env:get_objects_inside_radius(pos, 10) local objects = minetest.env:get_objects_inside_radius(pos, 10)
local flag = 0 local flag = 0
local vec = dropper:get_look_dir() local vec = dropper:get_look_dir()
local pos = dropper:getpos() local pos = dropper:getpos()
--vec.y = 0 --vec.y = 0
for i=1,10 do for i=1,epicenter_distance do
pos = vector.add(pos, vec) pos = vector.add(pos, vec)
end end
@ -740,6 +746,7 @@ minetest.register_tool("nssm:gratuitousness_battleaxe", {
}) })
minetest.register_tool("nssm:sword_of_eagerness", { minetest.register_tool("nssm:sword_of_eagerness", {
-- Cause enemies to be sent upwards y+20
description = "Sword of Eagerness", description = "Sword of Eagerness",
inventory_image = "sword_of_eagerness.png", inventory_image = "sword_of_eagerness.png",
wield_scale= {x=2,y=2,z=1}, wield_scale= {x=2,y=2,z=1},
@ -829,6 +836,7 @@ minetest.register_tool("nssm:sword_of_eagerness", {
}) })
minetest.register_tool("nssm:falchion_of_eagerness", { minetest.register_tool("nssm:falchion_of_eagerness", {
-- Sends player 16m in the direction in which they are pointing...
description = "Falchion of Eagerness", description = "Falchion of Eagerness",
inventory_image = "falchion_of_eagerness.png", inventory_image = "falchion_of_eagerness.png",
wield_scale= {x=2,y=2,z=1}, wield_scale= {x=2,y=2,z=1},
@ -843,11 +851,11 @@ minetest.register_tool("nssm:falchion_of_eagerness", {
}, },
on_drop = function(itemstack, dropper, pos) on_drop = function(itemstack, dropper, pos)
local vec = dropper:get_look_dir() local vec = dropper:get_look_dir()
local pos = dropper:getpos() local pos_destination = dropper:getpos()
--vec.y = 0 --vec.y = 0
for i=1,16 do for i=1,16 do
pos = vector.add(pos, vec) pos_destination = vector.add(pos_destination, vec)
end end
local pname = dropper:get_player_name() local pname = dropper:get_player_name()
@ -868,15 +876,20 @@ minetest.register_tool("nssm:falchion_of_eagerness", {
end end
end end
if found == 0 then if found == 0 then
minetest.chat_send_player(pname, "You haven't got enough life_energy!") minetest.chat_send_player(pname, "You do not have enough life energy!")
return return
elseif minetest.is_protected(pos_destination, pname) or nssm.unswappable_node(pos_destination) then
minetest.chat_send_player(pname, "You cannot go to that protected space!")
return
else else
local s = dropper:getpos() local pos_particles = dropper:getpos()
minetest.add_particlespawner( minetest.add_particlespawner(
25, --amount 25, --amount
0.3, --time 0.3, --time
vector.subtract(s, 0.5), --minpos vector.subtract(pos_particles, 0.5), --minpos
vector.add(s, 0.5), --maxpos vector.add(pos_particles, 0.5), --maxpos
{x=0, y=10, z=0}, --minvel {x=0, y=10, z=0}, --minvel
{x=0.1, y=11, z=0.1}, --maxvel {x=0.1, y=11, z=0.1}, --maxvel
{x=0,y=1,z=0}, --minacc {x=0,y=1,z=0}, --minacc
@ -888,19 +901,24 @@ minetest.register_tool("nssm:falchion_of_eagerness", {
false, --collisiondetection false, --collisiondetection
"slothful_soul_fragment.png" --texture "slothful_soul_fragment.png" --texture
) )
minetest.remove_node(pos)
pos.y=pos.y+1 local dy, digpos
minetest.remove_node(pos) for dy = -1,1 do
pos.y=pos.y-2 digpos = pos_destination + dy
minetest.remove_node(pos) if not nssm.unswappable_node(digpos) then
dropper:setpos(pos) minetest.remove_node(digpos)
s = pos end
s.y = s.y+10 end
dropper:setpos(pos_destination)
pos_particles = pos_destination
pos_particles.y = pos_particles.y+10
minetest.add_particlespawner( minetest.add_particlespawner(
25, --amount 25, --amount
0.3, --time 0.3, --time
vector.subtract(s, 0.5), --minpos vector.subtract(pos_particles, 0.5), --minpos
vector.add(s, 0.5), --maxpos vector.add(pos_particles, 0.5), --maxpos
{x=0, y=-10, z=0}, --minvel {x=0, y=-10, z=0}, --minvel
{x=0.1, y=-11, z=0.1}, --maxvel {x=0.1, y=-11, z=0.1}, --maxvel
{x=0,y=-1,z=0}, --minacc {x=0,y=-1,z=0}, --minacc
@ -912,6 +930,7 @@ minetest.register_tool("nssm:falchion_of_eagerness", {
false, --collisiondetection false, --collisiondetection
"slothful_soul_fragment.png" --texture "slothful_soul_fragment.png" --texture
) )
local items = player_inv:get_stack('main', found) local items = player_inv:get_stack('main', found)
items:set_count(items:get_count()-5) items:set_count(items:get_count()-5)
player_inv:set_stack('main', found, items) player_inv:set_stack('main', found, items)
@ -921,6 +940,8 @@ minetest.register_tool("nssm:falchion_of_eagerness", {
}) })
minetest.register_tool("nssm:sword_of_envy", { minetest.register_tool("nssm:sword_of_envy", {
-- Switch the health of the enemy with the health of the player
-- Particularly useful when enemy's health is over 20
description = "Sword of Envy", description = "Sword of Envy",
inventory_image = "sword_of_envy.png", inventory_image = "sword_of_envy.png",
wield_scale= {x=2,y=2,z=1}, wield_scale= {x=2,y=2,z=1},
@ -971,14 +992,18 @@ minetest.register_tool("nssm:sword_of_envy", {
end end
else else
if (obj:get_luaentity().health) then if (obj:get_luaentity().health) then
local hpp = obj:get_luaentity().health local obj_health = obj:get_luaentity().health
obj:get_luaentity().health = dropper:get_hp() obj:get_luaentity().health = dropper:get_hp()
if hpp > 20 then
if obj_health > 20 then
dropper:set_hp(20) dropper:set_hp(20)
else else
dropper:set_hp(hpp) dropper:set_hp(obj_health)
end
if obj:get_luaentity().check_for_death then
obj:get_luaentity():check_for_death({type = "punch"})
end end
check_for_death(obj:get_luaentity())
flag = 1 flag = 1
local items = player_inv:get_stack('main', found) local items = player_inv:get_stack('main', found)
@ -994,6 +1019,7 @@ minetest.register_tool("nssm:sword_of_envy", {
}) })
minetest.register_tool("nssm:sword_of_gluttony", { minetest.register_tool("nssm:sword_of_gluttony", {
-- Kills nearby monsters and causes them to drop roasted duck legs! :D
description = "Sword of Gluttony", description = "Sword of Gluttony",
inventory_image = "sword_of_gluttony.png", inventory_image = "sword_of_gluttony.png",
wield_scale= {x=2,y=2,z=1}, wield_scale= {x=2,y=2,z=1},
@ -1046,6 +1072,8 @@ minetest.register_tool("nssm:sword_of_gluttony", {
local pos = obj:getpos() local pos = obj:getpos()
obj:remove() obj:remove()
-- We don't use check_for_death, as that would cause it to put regular drops
-- (FIXME - this means hydra hobs do not respawn...)
--check_for_death(obj:get_luaentity()) --check_for_death(obj:get_luaentity())
--flag = 1 --flag = 1
--take energy globe from inventory: --take energy globe from inventory:
@ -1055,7 +1083,7 @@ minetest.register_tool("nssm:sword_of_gluttony", {
for i = 1,math.random(1,4) do for i = 1,math.random(1,4) do
drop = minetest.add_item(pos, "nssm:roasted_duck_legs 1") drop = minetest.add_item(pos, "nssm:roasted_duck_legs 1")
drops(drop) nssm.drops(drop)
end end
local s = obj:getpos() local s = obj:getpos()
@ -1089,6 +1117,8 @@ minetest.register_tool("nssm:sword_of_gluttony", {
}) })
minetest.register_tool("nssm:death_scythe", { minetest.register_tool("nssm:death_scythe", {
-- Kills everything around it
-- Casues dry grass, dry shrubs, and dead leaves, dropping lots of life eergy to drop too
description = "Death Scythe", description = "Death Scythe",
wield_scale= {x=3,y=3,z=1.3}, wield_scale= {x=3,y=3,z=1.3},
inventory_image = "death_scythe.png", inventory_image = "death_scythe.png",
@ -1116,7 +1146,9 @@ minetest.register_tool("nssm:death_scythe", {
else else
if (obj:get_luaentity().health) then if (obj:get_luaentity().health) then
obj:get_luaentity().health = obj:get_luaentity().health -40 obj:get_luaentity().health = obj:get_luaentity().health -40
check_for_death(obj:get_luaentity()) if obj:get_luaentity().check_for_death then
obj:get_luaentity():check_for_death({type = "punch"})
end
flag = 1 flag = 1
end end
end end
@ -1143,7 +1175,7 @@ minetest.register_tool("nssm:death_scythe", {
if math.random(1,3)==1 then if math.random(1,3)==1 then
v.y = v.y +2 v.y = v.y +2
drop = minetest.add_item(v, "nssm:life_energy 1") drop = minetest.add_item(v, "nssm:life_energy 1")
drops(drop) nssm.drops(drop)
end end
end end
@ -1154,7 +1186,7 @@ minetest.register_tool("nssm:death_scythe", {
if math.random(1,3)==1 then if math.random(1,3)==1 then
v.y = v.y +2 v.y = v.y +2
drop = minetest.add_item(v, "nssm:life_energy 1") drop = minetest.add_item(v, "nssm:life_energy 1")
drops(drop) nssm.drops(drop)
end end
end end
@ -1165,7 +1197,7 @@ minetest.register_tool("nssm:death_scythe", {
if math.random(1,3)==1 then if math.random(1,3)==1 then
v.y = v.y +2 v.y = v.y +2
drop = minetest.add_item(v, "nssm:life_energy 1") drop = minetest.add_item(v, "nssm:life_energy 1")
drops(drop) nssm.drops(drop)
end end
end end
end, end,

View File

@ -82,12 +82,16 @@ mobs:register_mob("nssm:lava_titan", {
}, },
do_custom = function (self) do_custom = function (self)
digging_attack(self, nil, self.run_velocity, {x=0, y=4, z=0}) digging_attack(self, nil, self.run_velocity, {x=0, y=4, z=0})
-- Deactivated because... non existent ?
--digging_ability(self, nil, self.run_velocity, {x=0, y=5, z=0}) --digging_ability(self, nil, self.run_velocity, {x=0, y=5, z=0})
-- For now deactivate - it places lava under it, sinks, then places lava under it, sinks, etc ...
--putting_ability(self, "default:lava_source", self.run_velocity) --putting_ability(self, "default:lava_source", self.run_velocity)
end, end,
--[[ --[[
custom_attack = function (self) custom_attack = function (self)
digging_attack -- digging_attack
mobs:set_animation(self, "punch") mobs:set_animation(self, "punch")
local p2 = p local p2 = p
local s2 = s local s2 = s
@ -113,5 +117,5 @@ mobs:register_mob("nssm:lava_titan", {
}, nil) }, nil)
end end
end, end,
]]-- --]]
}) })

View File

@ -1,7 +1,6 @@
Mobs bugs + changes Mobs bugs + changes
* Check why ice snake and snow biter are not placing ice * Ensure phoenix cannot burn through unswappable
* Check why lava titan is not placing lava
Server-oriented changes Server-oriented changes