--[[ NB More Concrete - Adds more concrete types to NodeCore Copyright (C) 2024, 2025 NameNotQuality This file is part of NB More Concrete. NB More Concrete is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. NB More Concrete is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with NB More Concrete. If not, see . This file includes modified code from the file `register.lua` from the `mods/nc_concrete` directory of the NodeCore Project, hosted on https://gitlab.com/sztest/nodecore. The NodeCore Project's license notice is below. Copyright (C)2018-2024 Aaron Suen Portions Copyright (C)2019-2020 LoneWolfHT Portions Copyright (C)2019 Magik Eh Portions Copyright (C)2019-2021 GreenXenith Portions Copyright (C)2019-2024 Dmitriy Tillyaev (Kimapr) Portions Copyright (C)2019 Elkien Portions Copyright (C)2020 WintersKnight94 Portions Copyright (C)2019 Avicennia G Portions Copyright (C)2022 MisterE Portions Copyright (C)2022 Giuseppe Bilotta Portions Copyright (C)2020 Yaman Qalieh Portions Copyright (C)2022 NoComment Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -- Lualocals to become able to use globals? -- LUALOCALS? > ---------------------------- local nc , core, include = nodecore, core, include -- LUALOCALS! < ---------------------------- -- mn - Mod Name shortcut instead of typing the full name (and easier to rename in forks) local mn = core.get_current_modname() -- This program is, once again, licensed under the AGPL-3.0-or-later. -- Here is a command that you can use to offer your modified source code (e.g. in a tarball): --[[ core.register_chatcommand("nb_more_concrete:source", { func = function(name) -- Change "(link)" to the URL where the source code is offered (preferably https://). core.chat_send_player(name, "The source of this program is offered here: (link)") return true end }) --]] -- Defining each concrete goes in a similar fashion. -- Here is a function to not repeat the same things: -- -- I don't want LUAnti letting me forget my C++! -- I need to make a C version of this! I still remember! chars for ints for more space saving! -- void define_the_concrete (char* name, char* desc, char crack, char* ingredient, char dmg, char* sounds, -- /* For some reason 3 in arrays here means 3 spaces instead of 4, skipping the 1st 0 */ -- char mcolor[3], char alpha, char bondalpha, char door_scuff, char door_volume, -- char patopacity, bool patinvert, char* psounds, char* mix, char* mixdesc, -- char scolor[3], bool regd, char* tiled, char* tilew) local function define_the_concrete(name, desc, tile, crack, ingredient, crude, washed, dmg, sounds, mcolor, alpha, bondalpha, door_scuff, door_volume, patopacity, patinvert, psounds, mix, mixdesc, scolor, craftd, regd, tiled, tilew) -- Arg examples: -- name = "chromete" -- desc = "Chromete" -- tile = "nb_more_concrete_chromete.png" -- crack = 3 -- cracky group -- ingredient = "nc_optics:glass_opaque" -- crude = "nc_optics:glass_crude" -- washed = "nc_terrain:sand" -- dmg = 2 -- fall damage -- sounds = "nc_terrain_stony" -- mcolor = {47, 72, 87} -- alpha = 128 -- bricks -- bondalpha = 64 -- bricks -- door_scuff = 60 -- hinge scuffs on the other side -- door_volume = 75 -- hinge -- patopacity = 32 -- pat-pattern -- patinvert = true -- inverts the shade, here its black, for false its white -- psounds = "nc_terrain_crunchy" -- p-pliant -- mix = "chromix" -- mixdesc = "Chromix" -- scolor = {37, 62, 77} -- swimcolor -- craftd = false -- register craft for dry (mix), false for custom craft or no mix -- regd = true -- register dry (mix) -- tiled = "^(nc_fire_ash.png^[mask:nc_concrete_mask.png)" -- tile dry (to cat with tile like this: tile .. tiled) -- tilew = "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png): -- tile wet -- [mask:nc_concrete_mask.png)" -- tile wet, which will cat with the png tile -- Extra variables so no constant concatinating is required local node = mn .. ":" .. name -- e.g. mn:chromete -- Creating concrete is easy. -- You can do it in 4 steps: --1. Define the node core.register_node(node, { description = desc, tiles = {tile}, groups = { cracky = crack, -- Group named as concrete [name] = 1 -- silktouch = true -- causes error, it turns out this property is dictated by hardness instead }, drop_in_place = ingredient, crush_damage = dmg, sounds = nc.sounds(sounds), mapcolor = mcolor }) --2. Stone Bricks nc.register_stone_bricks(name, desc, tile, -- tile alpha,bondalpha, -- alpha and boldalpha numbers for the brick texture node, -- made from {cracky = crack}, -- normal groups { -- bonded groups cracky = crack+1, nc_door_scuff_opacity = door_scuff, -- those white lines on the other side compared to the dark line with the handle door_operate_sound_volume = door_volume }, mcolor -- mapcolor ) --3. Register the pliant thing nc.register_concrete_etchable({ basename = node, pattern_opacity = patopacity, pattern_invert = patinvert, pliant = { sounds = nc.sounds(psounds), drop_in_place = "nc_concrete:" .. mix .. "_wet_source", -- e.g. nc_concrete:chromix_wet_source silktouch = false } }) -- String to cat with concrete name local localpref = "nc_concrete:" .. mn:gsub("^nc_", "") .. "_" -- e.g. nc_concrete:nb_more_concrete_chromete_blank_ply --4. And the actual concrete nc.register_concrete({ name = mix, description = mixdesc, -- Register mix can be false for e.g. +charcoal variants register_dry = regd, craft_mix = craftd, tile_powder = tile .. tiled, tile_wet = tile .. tilew, sound = psounds, groups_powder = {crumbly = crack}, swim_color = scolor, craft_from_keys = {ingredient}, craft_from = ingredient, to_crude = crude, to_washed = washed, to_molded = localpref .. name .. "_blank_ply", -- e.g. localpref .. chromete_blank_ply mapcolor = mcolor }) end ----- define_the_concrete -- local function define_the_concrete(name, desc, crack, ingredient, crude, washed, dmg, sounds, mcolor, alpha, tile, -- bondalpha, door_scuff, door_volume, patopacity, patinvert, psounds, mix, -- mixdesc, scolor, regd, tiled, tilew) -- (23 args) -- Chromete if (core.settings:get_bool("nb_more_concrete_blue",true)) then define_the_concrete("chromete", "Chromete", -- name and desc mn.."_chromete.png", -- tile 2, -- cracky "nc_optics:glass_opaque", -- very opaque ingredient "nc_optics:glass_crude", -- crude "nc_terrain:sand", -- washed 2, -- fall damage "nc_terrain_stony", -- concrete sound {r=47, b=72, g=87}, -- concrete mapcolor 133, 64, -- brick alpha and bondalpha 45, 75, -- door scuff opacity and noise 35, true, -- pattern opacity and invert shade "nc_terrain_crunchy", -- mix sounds "chromix", "Chromix", -- mix name and desc {37, 62, 77}, -- swimcolor false, true, -- craft dry/register dry "^(nc_optics_glass_sparkle.png^[opacity:33)^(nc_fire_ash.png^[mask:nc_concrete_mask.png)", -- tile dry "^(nc_optics_glass_sparkle.png^[opacity:26)^(nc_fire_ash.png^(nc_terrain_gravel.png" .. "^[opacity:128)^[mask:nc_concrete_mask.png)" -- tile wet ) -- By default, the concrete is mixable by hand. -- It may not make much sense by itself, but it -- becomes an even more apparent issue when the -- ingredient is a rock-hard glass. -- -- Earlier here I used a loop that found the -- right recipe through the table of all of them -- and then modified its thumpy group accordingly, -- but disabling registering a craft recipe by the -- above function and registering a custom craft here -- should be faster: nc.register_craft({ -- Fail label = "mix chromete (fail)", action = "pummel", normal = {y=1}, toolgroups = {thumpy=3}, -- The change consumewield=0, priority=2, -- So the next version doesn't replace this one nodes = { {match="nc_optics:glass_opaque", replace = "air"}, -- Check if building around is possible, which means that the ash is not surrounded properly {match={buildable_to=true}, x=1, y=-1}, {match="nc_fire:ash", replace="air", y=-1} }, -- Disperse the ash block and make the top ingredient fall before = function(pos) nc.item_disperse(pos, "nc_fire:lump_ash", 8) return nc.fall_force(pos) end -- after }) nc.register_craft({ -- Success label = "mix chromete", action = "pummel", normal = {y=1}, toolgroups = {thumpy=3}, -- The change consumewield = 0, priority=1, nodes = { {match = "nc_optics:glass_opaque", replace = "air"}, {match = "nc_fire:ash", replace = "nc_concrete:chromix", y=-1} } }) end -- Dark Chromete if (core.settings:get_bool("nb_more_concrete_darkchromete",true)) then define_the_concrete("dark_chromete", "Sea Chromete", mn.."_dark_chromete.png", -- tile 2, -- cracky "nc_optics:glass_opaque", -- ingredient (also used for block drop) "nc_optics:glass_crude", -- crude "nc_terrain:sand", -- washed 2, -- fall damage "nc_terrain_stony", -- concrete sound {r=27, b=52, g=67}, -- mapcolor (unfinished) 133,64, -- brick alpha/bondalpha 16,75, -- door scuff opacity and noise 50,false,-- pattern opacity and invert "nc_terrain_crunchy", -- mix sounds "dark_chromix", "Sea Chromix", -- mix name and desc {17, 42, 57}, -- swimcolor false, false, -- register dry mix "", -- tile dry (empty) "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png)" -- tile wet ) -- To get the Dark Chromete, one will need to add -- charcoal to the wet chromete mix in the same -- fashion as with aggregate. -- -- NodeCore uses a weird function to do this, but <- on_right_click and nc.item_entity_step -- I'm just going to make a craft. -- -- But is there a good reason why the game takes a -- different approach? -- -- -- EDIT: There is! You can just throw charcoal into -- aggregate or set up charcoal above aggregate before -- it gets wet so it turns darker. This recipe doesn't -- work that cool way. -- So I add additionally the item entity step and -- rightclick instead of craft -- Based on NC -- item entity step (coal fall into concrete) part nc.register_item_entity_step(function(self) -- Get/init the variables local stack = ItemStack(self.itemstring) if stack:get_name() ~= "nc_fire:lump_coal" then return end -- local pos = self.object:get_pos() if not pos then return end -- local node = core.get_node(pos) if node.name ~= "nc_concrete:chromix_wet_source" then return end -- Color with the charcoal nc.set_loud(pos,{name = "nc_concrete:dark_chromix_wet_source"}) -- Stack decrement stack:take_item(1) if stack:is_empty() then -- After dec stack may be 0 self.object:remove() return true end self.itemstring = stack:to_string() end) -- on_rightclick (direct mix with coal) part <- craft could've went in place of this, but maybe this is faster -- For ref: nc_concrete: chromix_wet_source or another reason is behind NC doing it -- nc_concrete:dark_chromix_wet_source local oldrc = nc.registered_nodes["nc_concrete:chromix_wet_source"].on_rightclick core.override_item("nc_concrete:chromix_wet_source", { on_rightclick = function(pos, node, clicker, stack, pt, ...) if stack:get_name() ~= "nc_fire:lump_coal" then -- Activate oldrc in case it was defined if oldrc then return oldrc(pos, node, clicker, stack, pt, ...) end -- Nodes place on indisplacable wet concrete mix if stack:get_definition().type == "node" then return core.item_place_node(stack, clicker, pt) end return stack end -- (stack == coal) case --nc.player_discover(clicker, "craft:" .. modname .. ":coalaggregate") nc.set_loud(pos, {name = "nc_concrete:dark_chromix_wet_source"}) stack:take_item(1) return stack end -- Upon testing this right click it actually -- doesn't allow placing items on the concrete -- contrary to other concretes. This bug is in -- NC too, not sure if to fix and/or report -- though, it seems really unapparent? }) end -- Green Concrete if (core.settings:get_bool("nb_more_concrete_green",true)) then if (not core.settings:get_bool("nb_more_concrete_old_green_recipe")) then -- Recipe Switch define_the_concrete("green", "Green Concrete", mn.."_green.png", -- tile 1, -- cracky "nc_terrain:dirt", -- ingredient "nc_terrain:dirt", -- crude "nc_terrain:dirt", -- washed 1, -- fall dmg "nc_terrain_stony", -- sounds {r=15, b=15, g=3}, -- mapcolor 240,120, -- brick alphas 16,100, -- door scuff opacity and noise 46, false, -- pattern opacity and invert "nc_terrain_crunchy", -- mix sounds "green_mix", "Green Aggregate", -- mix name and desc {15, 15, 3}, -- swim color false, true, -- craft/define dry -- tile dry "^(nc_terrain_dirt.png^[opacity:50)^(nc_fire_ash.png^(nc_terrain_dirt.png^[opacity:40)^[mask:nc_concrete_mask.png)", -- tile wet "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png)" ) -- Peat is quite expensive like for concrete. -- Earlier it was used for the ingredient, but -- now all it requires is mixing loose leaves into adobe: nc.register_craft({ -- Fail label = "mix green aggregate (fail)", action = "pummel", normal = {y=1}, toolgroups = {thumpy=1}, consumewield=0, priority=2, nodes = { {match="nc_tree:leaves_loose"}, -- Leaves -- Check if building around is possible, which means that the mud is not surrounded properly for an epic fail {match={buildable_to=true}, x=1, y=-1}, {match="nc_concrete:mud", y=-1} -- Adobe mix = mud??? }, -- Instead of dispersing the mud into dirt and ash (which would make only adobe mix recyclable, -- which would not make sense next to other mixes), just make the leaves slip off before = function(pos) return nc.falling_repose_check(pos) end -- after }) nc.register_craft({ -- Not fail label = "mix green aggregate", action = "pummel", normal = {y=1}, toolgroups = {thumpy=1}, consumewield = 0, priority=1, nodes = { {match = "nc_tree:leaves_loose", replace = "air"}, -- Leaves {match = "nc_concrete:mud", replace = "nc_concrete:green_mix", y=-1} -- Mud -> Green mix } }) -- Green Concrete 1 (greener concrete) if (core.settings:get_bool("nb_more_concrete_greener",true)) then define_the_concrete("green1", "Green Concrete", -- Same desc mn.."_green1.png", -- tile 1, -- cracky "nc_terrain:dirt", -- ingredient "nc_terrain:dirt", -- crude "nc_terrain:dirt", -- washed 1, -- fall dmg "nc_terrain_stony", -- sounds {r=15, b=15, g=3}, -- mapcolor 240,120, -- brick alphas 16,100, -- door scuff opacity and noise 46, false, -- pattern opacity and invert "nc_terrain_crunchy", -- mix sounds "green1_mix", "Green Aggregate", -- mix name and desc {16, 17, 2}, -- swim color false, true, -- still craft/define dry -- tile dry "^(nc_terrain_dirt.png^[opacity:40)^(nc_fire_ash.png^(nc_terrain_dirt.png^[opacity:40)^[mask:nc_concrete_mask.png)", -- tile wet "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png)" ) -- Crafts similar to earlier -- You can make the greener concrete by making the green -- concrete even greener (add leaves again). nc.register_craft({ -- Fail label = "mix greener aggregate (fail)", action = "pummel", normal = {y=1}, toolgroups = {thumpy=1}, consumewield=0, priority=2, nodes = { {match="nc_tree:leaves_loose"}, -- Leaves {match={buildable_to=true}, x=1, y=-1}, -- Area around {match="nc_concrete:green_mix", y=-1} -- Green mix }, before = function(pos) -- slip return nc.falling_repose_check(pos) end }) nc.register_craft({ -- Not fail label = "mix greener aggregate", action = "pummel", normal = {y=1}, toolgroups = {thumpy=1}, consumewield = 0, priority=1, nodes = { {match = "nc_tree:leaves_loose", replace = "air"}, -- Leaves {match = "nc_concrete:green_mix", replace = "nc_concrete:green1_mix", y=-1} -- Green mix -> Green1 mix } }) end -- Greener concrete --------Old Recipe------- else -- If some people want to keep the recipe the same as -- earlier (perhaps to later change it after recovering -- their peat back, which I wouldn't call cheating), -- here it is define_the_concrete("green", "Green Concrete", mn.."_green.png", -- tile 1, -- cracky -- Change from dirt to peat "nc_tree:peat", -- ingredient "nc_tree:peat", -- crude "nc_tree:peat", -- washed -- 1, -- fall dmg "nc_terrain_stony", -- sounds {r=15, b=15, g=3}, -- mapcolor 240,120, -- brick alphas 16,100, -- door scuff opacity and noise 46, false, -- pattern opacity and invert "nc_terrain_crunchy", -- mix sounds "green_mix", "Green Aggregate", -- mix name and desc {15, 15, 3}, -- swim color -- Change to make craft true, true, -- craft/define dry -- -- tile dry "^(nc_terrain_dirt.png^[opacity:50)^(nc_fire_ash.png^(nc_terrain_dirt.png^[opacity:40)^[mask:nc_concrete_mask.png)", -- tile wet "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png)" ) -- Green Concrete 1 if (core.settings:get_bool("nb_more_concrete_greener",true)) then define_the_concrete("green1", "Green Concrete", -- Same desc mn.."_green1.png", -- tile 1, -- cracky "nc_tree:peat", -- ingredient "nc_tree:peat", -- crude "nc_tree:peat", -- washed 1, -- fall dmg "nc_terrain_stony", -- sounds {r=15, b=15, g=3}, -- mapcolor 240,120, -- brick alphas 16,100, -- door scuff opacity and noise 46, false, -- pattern opacity and invert "nc_terrain_crunchy", -- mix sounds "green1_mix", "Green Aggregate", -- mix name and desc {16, 17, 2}, -- swim color false, true, -- still craft/define dry -- tile dry "^(nc_terrain_dirt.png^[opacity:40)^(nc_fire_ash.png^(nc_terrain_dirt.png^[opacity:40)^[mask:nc_concrete_mask.png)", -- tile wet "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png)" ) -- To make the concrete greener, this time the craft is going to -- be the same like for the new recipe. This way, a peat-mix is -- going to have leaves added, like if only peat could mix with leaves -- or got added extra leaves/peat material. nc.register_craft({ -- Fail label = "mix greener aggregate (fail)", action = "pummel", normal = {y=1}, toolgroups = {thumpy=1}, consumewield=0, priority=2, nodes = { {match="nc_tree:leaves_loose"}, -- Leaves {match={buildable_to=true}, x=1, y=-1}, -- Area around {match="nc_concrete:green_mix", y=-1} -- Green mix }, before = function(pos) -- slip return nc.falling_repose_check(pos) end }) nc.register_craft({ -- Not fail label = "mix greener aggregate", action = "pummel", normal = {y=1}, toolgroups = {thumpy=1}, consumewield = 0, priority=1, nodes = { {match = "nc_tree:leaves_loose", replace = "air"}, -- Leaves {match = "nc_concrete:green_mix", replace = "nc_concrete:green1_mix", y=-1} -- Green mix -> Green 1 mix } }) end -- Green Concrete 1 end -- Recipe switch end -- Green Concrete -- Amberstone! -- Formely 'Gluestone' and 'Eggstone', -- Renamed so it sounds cool instead of weird if (core.settings:get_bool("nb_more_concrete_orange",true)) then -- After changing the description to 'Amberstone' I can't simply change -- the technical name too, as else it would break existing worlds... -- Except if I would alias 24 items? define_the_concrete("eggstone", "Amberstone", -- The eggcorn's coloring isn't as powerful as charcoal, so -- the texture is not going to have a vibrant orange color, -- unlike the next amberstone made with 1 more eggcorn. "nc_concrete_cloudstone.png^[colorize:#FF7F0045", -- texture 1, -- crackyness "nc_optics:glass_crude", -- ingredient "nc_optics:glass_crude", -- crude "nc_optics:glass_crude", -- washed 1, -- fall dmg "nc_terrain_stony", -- sound {r=88,g=77,b=61}, -- mapcolor 120,64, -- brick alphas 55,100, -- door scuff opacity and noise 33,true, -- pattern opacity and invert "nc_terrain_crunchy", -- mix sounds "egg_mix", "Ambery Spackling", -- mix name and desc {78, 67, 51}, -- swimcolor false, false, -- craft/define dry "", -- tile dry "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png)" -- tile wet ) -- To get Gluey Spackling, it is going to be required -- to pummel a wet Spackling with an eggcorn, similarly -- to sticking an optic in place. nc.register_craft({ label = "mix eggcorn with spackling", action = "pummel", wield = {name = "nc_tree:eggcorn"}, consumewield = 1, duration = 1, nodes = { {match = "nc_concrete:cloudmix_wet_source", replace = "nc_concrete:egg_mix_wet_source"} } }) -- Should I add a setting so instead only right-clicking with the eggcorn is required? -- Or make that a default? -- Amberstone 1 (more vibrant Amberstone that you can get by pummeling it with another eggcorn) -- It will have same descs as previous Amberstone (similarly to e.g. harder and darker stone variants) if (core.settings:get_bool("nb_more_concrete_orange1",true)) then define_the_concrete("egg1stone", "Amberstone", -- name kept similar to previous amberstone for consistency "nc_concrete_cloudstone.png^[colorize:#FF8F0A64", -- texture 1, -- crackyness "nc_optics:glass_crude", -- ingredient "nc_optics:glass_crude", -- crude "nc_optics:glass_crude", -- washed 2, -- fall dmg "nc_terrain_stony", -- sound {r=90,g=73,b=54}, -- mapcolor 120,64, -- brick alphas 55,100, -- door scuff opacity and noise 33,true, -- pattern opacity and invert "nc_terrain_crunchy", -- mix sounds "egg1_mix", "Ambery Spackling", -- mix name and desc {80, 63, 44}, -- swimcolor false, false, -- craft/define dry "", -- tile dry "^(nc_fire_ash.png^(nc_terrain_gravel.png^[opacity:128)^[mask:nc_concrete_mask.png)" -- tile wet ) -- Similar craft to earlier nc.register_craft({ label = "mix eggcorn with ambery spackling", action = "pummel", wield = {name = "nc_tree:eggcorn"}, consumewield = 1, duration = 1, nodes = { {match = "nc_concrete:egg_mix_wet_source", replace = "nc_concrete:egg1_mix_wet_source"} } }) end -- Orange1 end -- Orange -- After defining all of the concretes, let's add more patterns... if (core.settings:get_bool("nb_more_concrete_stylus",true)) then include("lode_stylus.lua") end