/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "lua_api/l_craft.h" #include "lua_api/l_internal.h" #include "lua_api/l_item.h" #include "common/c_converter.h" #include "common/c_content.h" #include "server.h" #include "craftdef.h" struct EnumString ModApiCraft::es_CraftMethod[] = { {CRAFT_METHOD_NORMAL, "normal"}, {CRAFT_METHOD_COOKING, "cooking"}, {CRAFT_METHOD_FUEL, "fuel"}, {0, NULL}, }; // helper for register_craft bool ModApiCraft::readCraftRecipeShaped(lua_State *L, int index, int &width, std::vector &recipe) { if(index < 0) index = lua_gettop(L) + 1 + index; if(!lua_istable(L, index)) return false; lua_pushnil(L); int rowcount = 0; while(lua_next(L, index) != 0){ int colcount = 0; // key at index -2 and value at index -1 if(!lua_istable(L, -1)) return false; int table2 = lua_gettop(L); lua_pushnil(L); while(lua_next(L, table2) != 0){ // key at index -2 and value at index -1 if(!lua_isstring(L, -1)) return false; recipe.emplace_back(readParam(L, -1)); // removes value, keeps key for next iteration lua_pop(L, 1); colcount++; } if(rowcount == 0){ width = colcount; } else { if(colcount != width) return false; } // removes value, keeps key for next iteration lua_pop(L, 1); rowcount++; } return width != 0; } // helper for register_craft bool ModApiCraft::readCraftRecipeShapeless(lua_State *L, int index, std::vector &recipe) { if(index < 0) index = lua_gettop(L) + 1 + index; if(!lua_istable(L, index)) return false; lua_pushnil(L); while(lua_next(L, index) != 0){ // key at index -2 and value at index -1 if(!lua_isstring(L, -1)) return false; recipe.emplace_back(readParam(L, -1)); // removes value, keeps key for next iteration lua_pop(L, 1); } return true; } // helper for register_craft bool ModApiCraft::readCraftReplacements(lua_State *L, int index, CraftReplacements &replacements) { if(index < 0) index = lua_gettop(L) + 1 + index; if(!lua_istable(L, index)) return false; lua_pushnil(L); while(lua_next(L, index) != 0){ // key at index -2 and value at index -1 if(!lua_istable(L, -1)) return false; lua_rawgeti(L, -1, 1); if(!lua_isstring(L, -1)) return false; std::string replace_from = readParam(L, -1); lua_pop(L, 1); lua_rawgeti(L, -1, 2); if(!lua_isstring(L, -1)) return false; std::string replace_to = readParam(L, -1); lua_pop(L, 1); replacements.pairs.emplace_back(replace_from, replace_to); // removes value, keeps key for next iteration lua_pop(L, 1); } return true; } // register_craft({output=item, recipe={{item00,item10},{item01,item11}}) int ModApiCraft::l_register_craft(lua_State *L) { NO_MAP_LOCK_REQUIRED; //infostream<<"register_craft"<getWritableCraftDefManager(); std::string type = getstringfield_default(L, table, "type", "shaped"); /* CraftDefinitionShaped */ if(type == "shaped"){ std::string output = getstringfield_default(L, table, "output", ""); if (output.empty()) throw LuaError("Crafting definition is missing an output"); int width = 0; std::vector recipe; lua_getfield(L, table, "recipe"); if(lua_isnil(L, -1)) throw LuaError("Crafting definition is missing a recipe" " (output=\"" + output + "\")"); if(!readCraftRecipeShaped(L, -1, width, recipe)) throw LuaError("Invalid crafting recipe" " (output=\"" + output + "\")"); CraftReplacements replacements; lua_getfield(L, table, "replacements"); if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) throw LuaError("Invalid replacements" " (output=\"" + output + "\")"); } CraftDefinition *def = new CraftDefinitionShaped( output, width, recipe, replacements); craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionShapeless */ else if(type == "shapeless"){ std::string output = getstringfield_default(L, table, "output", ""); if (output.empty()) throw LuaError("Crafting definition (shapeless)" " is missing an output"); std::vector recipe; lua_getfield(L, table, "recipe"); if(lua_isnil(L, -1)) throw LuaError("Crafting definition (shapeless)" " is missing a recipe" " (output=\"" + output + "\")"); if(!readCraftRecipeShapeless(L, -1, recipe)) throw LuaError("Invalid crafting recipe" " (output=\"" + output + "\")"); CraftReplacements replacements; lua_getfield(L, table, "replacements"); if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) throw LuaError("Invalid replacements" " (output=\"" + output + "\")"); } CraftDefinition *def = new CraftDefinitionShapeless( output, recipe, replacements); craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionToolRepair */ else if(type == "toolrepair"){ float additional_wear = getfloatfield_default(L, table, "additional_wear", 0.0); CraftDefinition *def = new CraftDefinitionToolRepair( additional_wear); craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionCooking */ else if(type == "cooking"){ std::string output = getstringfield_default(L, table, "output", ""); if (output.empty()) throw LuaError("Crafting definition (cooking)" " is missing an output"); std::string recipe = getstringfield_default(L, table, "recipe", ""); if (recipe.empty()) throw LuaError("Crafting definition (cooking)" " is missing a recipe" " (output=\"" + output + "\")"); float cooktime = getfloatfield_default(L, table, "cooktime", 3.0); CraftReplacements replacements; lua_getfield(L, table, "replacements"); if(!lua_isnil(L, -1)) { if(!readCraf#!/bin/bash die() { echo "$@" 1>&2 ; exit 1; } prompt_for_number() { local prompt_text=$1 local default_value=$2 local tmp="" while true; do read -p "$prompt_text [$default_value]: " tmp if [ "$tmp" = "" ]; then echo "$default_value"; return elif echo "$tmp" | grep -q -E '^[0-9]+$'; then echo "$tmp"; return fi done } ################################## # Switch to top minetest directory ################################## cd ${0%/*}/.. ####################### # Determine old version ####################### # Make sure all the files we need exist grep -q -E '^set\(VERSION_MAJOR [0-9]+\)$' CMakeLists.txt || die "error: Could not find CMakeLists.txt" grep -q -E '^set\(VERSION_MINOR [0-9]+\)$' CMakeLists.txt || die "error: Could not find CMakeLists.txt" grep -q -E '^set\(VERSION_PATCH [0-9]+\)$' CMakeLists.txt || die "error: Could not find CMakeLists.txt" grep -q -E 'versionCode [0-9]+$' build/android/build.gradle || die "error: Could not find Android version code" VERSION_MAJOR=$(grep -E '^set\(VERSION_MAJOR [0-9]+\)$' CMakeLists.txt | tr -dC 0-9) VERSION_MINOR=$(grep -E '^set\(VERSION_MINOR [0-9]+\)$' CMakeLists.txt | tr -dC 0-9) VERSION_PATCH=$(grep -E '^set\(VERSION_PATCH [0-9]+\)$' CMakeLists.txt | tr -dC 0-9) ANDROID_VERSION_CODE=$(grep -E 'versionCode [0-9]+$' build/android/build.gradle | tr -dC 0-9) echo "Current Minetest version: $VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" echo "Current Android version code: $ANDROID_VERSION_CODE" ######################## # Prompt for new version ######################## NEW_VERSION_MAJOR=$VERSION_MAJOR NEW_VERSION_MINOR=$VERSION_MINOR NEW_VERSION_PATCH=$(expr $VERSION_PATCH + 1) NEW_VERSION_MAJOR=$(prompt_for_number "Set major" $NEW_VERSION_MAJOR) gdef, *it, output); lua_rawseti(L, -2, ++i); } } // get_craft_recipe(result item) int ModApiCraft::l_get_craft_recipe(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::string item = luaL_checkstring(L, 1); Server *server = getServer(L); CraftOutput output(item, 0); std::vector recipes = server->cdef() ->getCraftRecipes(output, server, 1); lua_createtable(L, 1, 0); if (recipes.empty()) { lua_pushnil(L); lua_setfield(L, -2, "items"); setintfield(L, -1, "width", 0); return 1; } push_craft_recipe(L, server, recipes[0], output); return 1; } // get_all_craft_recipes(result item) int ModApiCraft::l_get_all_craft_recipes(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::string item = luaL_checkstring(L, 1); Server *server = getServer(L); CraftOutput output(item, 0); std::vector recipes = server->cdef() ->getCraftRecipes(output, server); push_craft_recipes(L, server, recipes, output); return 1; } void ModApiCraft::Initialize(lua_State *L, int top) { API_FCT(get_all_craft_recipes); API_FCT(get_craft_recipe); API_FCT(get_craft_result); API_FCT(register_craft); API_FCT(clear_craft); }