From b32db2cf4b044e997aa94b7c4d855995e0125e4a Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Sun, 11 Aug 2024 23:58:35 -0400 Subject: [PATCH 01/18] all parts --- .github/workflows/autowiki.yml | 49 + .gitignore | 3 + code/_compile_options.dm | 4 + .../subsystem/processing/station.dm | 3 +- code/game/mecha/mech_fabricator.dm | 4 +- code/game/world.dm | 4 + code/modules/autowiki/autowiki.dm | 33 + code/modules/autowiki/pages/base.dm | 54 + code/modules/autowiki/pages/soup.dm | 135 +++ code/modules/autowiki/pages/stockparts.dm | 89 ++ code/modules/autowiki/pages/techweb.dm | 68 ++ code/modules/autowiki/pages/vending.dm | 56 + code/modules/research/designs.dm | 8 +- .../modules/research/techweb/_techweb_node.dm | 6 +- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/autowiki.dm | 35 + tools/autowiki/autowiki.js | 83 ++ tools/autowiki/package-lock.json | 1043 +++++++++++++++++ tools/autowiki/package.json | 10 + 19 files changed, 1683 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/autowiki.yml create mode 100644 code/modules/autowiki/autowiki.dm create mode 100644 code/modules/autowiki/pages/base.dm create mode 100644 code/modules/autowiki/pages/soup.dm create mode 100644 code/modules/autowiki/pages/stockparts.dm create mode 100644 code/modules/autowiki/pages/techweb.dm create mode 100644 code/modules/autowiki/pages/vending.dm create mode 100644 code/modules/unit_tests/autowiki.dm create mode 100644 tools/autowiki/autowiki.js create mode 100644 tools/autowiki/package-lock.json create mode 100644 tools/autowiki/package.json diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml new file mode 100644 index 000000000000..740b5d7d9eb2 --- /dev/null +++ b/.github/workflows/autowiki.yml @@ -0,0 +1,49 @@ +name: Autowiki +on: + schedule: + - cron: "5 4 * * *" + workflow_dispatch: +permissions: + contents: read + +jobs: + autowiki: + runs-on: ubuntu-latest + steps: + - name: "Check for AUTOWIKI_USERNAME" + id: secrets_set + env: + ENABLER_SECRET: ${{ secrets.AUTOWIKI_USERNAME }} + run: | + unset SECRET_EXISTS + if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi + echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT + - name: Checkout + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/checkout@v4 + - name: Restore BYOND cache + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/cache@v4 + with: + path: ~/BYOND + key: ${{ runner.os }}-byond-${{ hashFiles('dependencies.sh') }} + - name: Install rust-g + if: steps.secrets_set.outputs.SECRETS_ENABLED + run: | + bash tools/ci/install_rust_g.sh + - name: Compile and generate Autowiki files + if: steps.secrets_set.outputs.SECRETS_ENABLED + run: | + bash tools/ci/install_byond.sh + source $HOME/BYOND/byond/bin/byondsetup + tools/build/build --ci autowiki + - name: Run Autowiki + if: steps.secrets_set.outputs.SECRETS_ENABLED + env: + USERNAME: ${{ secrets.AUTOWIKI_USERNAME }} + PASSWORD: ${{ secrets.AUTOWIKI_PASSWORD }} + run: | + cd tools/autowiki + npm install + cd ../.. + node tools/autowiki/autowiki.js data/autowiki_edits.txt data/autowiki_files/ diff --git a/.gitignore b/.gitignore index abbb15bf00f6..cd9b91afc153 100644 --- a/.gitignore +++ b/.gitignore @@ -225,3 +225,6 @@ tools/MapAtmosFixer/MapAtmosFixer/bin/* # Running OpenDream locally tgstation.json + +# Autowiki +/tools/autowiki/node_modules diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 341180f4bb42..debcdc1da52a 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -23,6 +23,10 @@ // If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between //#define UNIT_TESTS +/// If this is uncommented, Autowiki will generate edits and shut down the server. +/// Prefer the autowiki build target instead. +// #define AUTOWIKI + // If defined, we will NOT defer asset generation till later in the game, and will instead do it all at once, during initiialize //#define DO_NOT_DEFER_ASSETS diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm index a2589f3f7914..fe56621f00ee 100644 --- a/code/controllers/subsystem/processing/station.dm +++ b/code/controllers/subsystem/processing/station.dm @@ -19,7 +19,8 @@ PROCESSING_SUBSYSTEM_DEF(station) /datum/controller/subsystem/processing/station/Initialize(timeofday) //If doing unit tests we don't do none of that trait shit ya know? - #ifndef UNIT_TESTS + // Autowiki also wants consistent outputs, for example making sure the vending machine page always reports the normal products + #if !defined(UNIT_TESTS) && !defined(AUTOWIKI) SetupTraits() PrepareReport() #endif diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 75d11b4379e9..6fe6fe243123 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -258,7 +258,7 @@ var/list/part = list( "name" = D.name, - "desc" = initial(built_item.desc), + "desc" = D.get_description(), "printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10, "cost" = cost, "id" = D.id, @@ -272,7 +272,7 @@ /** * Generates a list of resources / materials available to this Exosuit Fab * - * Returns null if there is no material container available. + * Returns null if there is no material container available.B * List format is list(material_name = list(amount = ..., ref = ..., etc.)) */ /obj/machinery/mecha_part_fabricator/proc/output_available_resources() diff --git a/code/game/world.dm b/code/game/world.dm index 53e3fe22b904..c37083d7d2a8 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -87,6 +87,10 @@ GLOBAL_VAR(restart_counter) HandleTestRun() #endif +#ifdef AUTOWIKI + setup_autowiki() +#endif + /world/proc/HandleTestRun() //trigger things to run the whole process Master.sleep_offline_after_initializations = FALSE diff --git a/code/modules/autowiki/autowiki.dm b/code/modules/autowiki/autowiki.dm new file mode 100644 index 000000000000..f7a7d957c3e1 --- /dev/null +++ b/code/modules/autowiki/autowiki.dm @@ -0,0 +1,33 @@ +/// When the `AUTOWIKI` define is enabled, will generate an output file for tools/autowiki/autowiki.js to consume. +/// Autowiki code intentionally still *exists* even without the define, to ensure developers notice +/// when they break it immediately, rather than until CI or worse, call time. +#if defined(AUTOWIKI) || defined(UNIT_TESTS) +/proc/setup_autowiki() + Master.sleep_offline_after_initializations = FALSE + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(generate_autowiki))) + SSticker.start_immediately = TRUE + CONFIG_SET(number/round_end_countdown, 0) + +/proc/generate_autowiki() + var/output = generate_autowiki_output() + rustg_file_write(output, "data/autowiki_edits.txt") + qdel(world) +#endif + +/// Returns a string of the autowiki output file +/proc/generate_autowiki_output() + var/total_output = "" + + for (var/datum/autowiki/autowiki_type as anything in subtypesof(/datum/autowiki)) + var/datum/autowiki/autowiki = new autowiki_type + var/output = autowiki.generate() + + if (!istext(output)) + CRASH("[autowiki_type] does not generate a proper output!") + + total_output += json_encode(list( + "title" = autowiki.page, + "text" = output, + )) + "\n" + + return total_output diff --git a/code/modules/autowiki/pages/base.dm b/code/modules/autowiki/pages/base.dm new file mode 100644 index 000000000000..8e745ace61c2 --- /dev/null +++ b/code/modules/autowiki/pages/base.dm @@ -0,0 +1,54 @@ +/// A representation of an automated wiki page. +/datum/autowiki + /// The page on the wiki to be replaced. + /// This should never be a user-facing page, like "Guide to circuits". + /// It should always be a template that only Autowiki should touch. + /// For example: "Template:Autowiki/CircuitInfo". + var/page + +/// Override and return the new text of the page. +/// This proc can be impure, usually to call `upload_file`. +/datum/autowiki/proc/generate() + SHOULD_CALL_PARENT(FALSE) + CRASH("[type] does not implement generate()!") + +/// Generates an auto formatted template user. +/// Your autowiki should ideally be a *lot* of these. +/// It lets wiki editors edit it much easier later, without having to enter repo. +/// Parameters will be passed in by name. That means your template should expect +/// something that looks like `{{ Autowiki_Circuit|name=Combiner|description=This combines }}` +/// Lists, which must be array-like (no keys), will be turned into a flat list with their key and a number, +/// such that list("food" = list("fruit", "candy")) -> food1=fruit|food2=candy +/datum/autowiki/proc/include_template(name, parameters) + var/template_text = "{{[name]" + + var/list/prepared_parameters = list() + for (var/key in parameters) + var/value = parameters[key] + if (islist(value)) + for (var/index in 1 to length(value)) + prepared_parameters["[key][index]"] = "[value[index]]" + else + prepared_parameters[key] = value + + for (var/parameter_name in prepared_parameters) + template_text += "|[parameter_name]=" + template_text += "[prepared_parameters[parameter_name]]" + + template_text += "}}" + + return template_text + +/// Takes an icon and uploads it to Autowiki-name.png. +/// Do your best to make sure this is unique, so it doesn't clash with other autowiki icons. +/datum/autowiki/proc/upload_icon(icon/icon, name) + // Fuck you + if (IsAdminAdvancedProcCall()) + return + + fcopy(icon, "data/autowiki_files/[name].png") + +/// Escape a parameter such that it can be correctly put inside a wiki output +/datum/autowiki/proc/escape_value(parameter) + // | is a special character in MediaWiki, and must be escaped by...using another template. + return replacetextEx(parameter, "|", "{{!}}") diff --git a/code/modules/autowiki/pages/soup.dm b/code/modules/autowiki/pages/soup.dm new file mode 100644 index 000000000000..75521005d8e8 --- /dev/null +++ b/code/modules/autowiki/pages/soup.dm @@ -0,0 +1,135 @@ +/datum/autowiki/soup + page = "Template:Autowiki/Content/SoupRecipes" + +/datum/autowiki/soup/generate() + var/output = "" + + // Since we're here, generate a range icon since that's what is installed in most kitchens + var/obj/machinery/oven/range/range = new() + upload_icon(getFlatIcon(range, no_anim = TRUE), "kitchen_range") + qdel(range) + + // Also generate a soup pot icon, as that's what makes soup + var/obj/item/reagent_containers/cup/soup_pot/soup_pot = new() + upload_icon(getFlatIcon(soup_pot, no_anim = TRUE), "soup_pot") + qdel(soup_pot) + + var/container_for_images = /obj/item/reagent_containers/cup/bowl + + for(var/soup_recipe_type in subtypesof(/datum/chemical_reaction/food/soup)) + var/datum/chemical_reaction/food/soup/soup_recipe = new soup_recipe_type() + // Used to determine what icon is displayed on the wiki + var/soup_icon + var/soup_icon_state + // Used to determine what food types the soup is + var/soup_food_types = NONE + // Used for filename and description of the result + var/result_name + var/result_desc + var/result_tastes + // Solid food item results take priority over reagents for showcasing results + if(soup_recipe.resulting_food_path) + var/obj/item/resulting_food = new soup_recipe.resulting_food_path() + result_name = format_text(resulting_food.name) + result_desc = resulting_food.desc + + soup_icon = resulting_food.icon + soup_icon_state = resulting_food.icon_state + + if(istype(resulting_food, /obj/item/food)) + var/obj/item/food/resulting_food_casted = resulting_food + result_tastes = resulting_food_casted.tastes?.Copy() + soup_food_types = resulting_food_casted.foodtypes || NONE + + qdel(resulting_food) + + // Otherwise, it should be a reagent. + else + var/result_soup_type = soup_recipe.results[1] + var/datum/reagent/result_soup = new result_soup_type() + result_name = format_text(result_soup.name) + result_desc = result_soup.description + result_tastes = result_soup.get_taste_description() + + var/datum/glass_style/has_foodtype/soup_style = GLOB.glass_style_singletons[container_for_images][result_soup_type] + soup_icon = soup_style.icon + soup_icon_state = soup_style.icon_state + soup_food_types = soup_style.drink_type + + qdel(result_soup) + + var/filename = "soup_[SANITIZE_FILENAME(escape_value(result_name))]" + + // -- Compiles a list of required reagents and food items -- + var/list/all_needs_text = list() + for(var/datum/reagent/reagent_type as anything in soup_recipe.required_reagents) + all_needs_text += "[soup_recipe.required_reagents[reagent_type]] units [initial(reagent_type.name)]" + for(var/datum/reagent/reagent_type as anything in soup_recipe.required_catalysts) + all_needs_text += "[soup_recipe.required_catalysts[reagent_type]] units [initial(reagent_type.name)] (not consumed)" + + for(var/obj/item/food_type as anything in soup_recipe.required_ingredients) + var/num_needed = soup_recipe.required_ingredients[food_type] + // Instantiating this so we can do plurality correctly. + // We can use initial but it'll give us stuff like "eyballss". + var/obj/item/food = new food_type() + all_needs_text += "[num_needed] [food.name]\s" + qdel(food) + + all_needs_text += soup_recipe.describe_recipe_details() + all_needs_text += "At temperature [soup_recipe.required_temp]K" + var/compiled_requirements = "" + for(var/req_text in all_needs_text) + if(length(req_text)) + compiled_requirements += "
  • [req_text]
  • " + if(length(compiled_requirements)) + compiled_requirements = "" + + // -- Compiles a list of resulting reagents -- + var/list/all_results_text = list() + for(var/datum/reagent/reagent_type as anything in soup_recipe.results) + var/num_given = soup_recipe.results[reagent_type] + all_results_text += "[num_given] units [initial(reagent_type.name)]" + if(soup_recipe.resulting_food_path) + all_results_text += "1 [initial(soup_recipe.resulting_food_path.name)]" + + all_results_text += soup_recipe.describe_result() + var/compiled_results = "" + for(var/res_text in all_results_text) + if(length(res_text)) + compiled_results += "
  • [res_text]
  • " + if(length(compiled_results)) + compiled_results = "" + + // -- Assemble the template list -- + var/list/template_list = list() + if(istype(soup_recipe, /datum/chemical_reaction/food/soup/custom)) + // Painful snowflaking here for custom recipes, + // but because they default to "bowl of water" we can't let it generate fully on its own. + template_list["name"] = "Custom Soup" + template_list["taste"] = "Whatever you use." + template_list["foodtypes"] = "Whatever you use." + template_list["description"] = "A custom soup recipe, allowing you to throw whatever you want in the pot." + + else + var/foodtypes_readable = jointext(bitfield_to_list(soup_food_types, FOOD_FLAGS_IC), ", ") || "None" + template_list["name"] = escape_value(result_name) + template_list["taste"] = escape_value(length(result_tastes) ? capitalize(jointext(result_tastes, ", ")) : "No taste") + template_list["foodtypes"] = escape_value(foodtypes_readable) + template_list["description"] = escape_value(result_desc) + + template_list["icon"] = escape_value(filename) + template_list["requirements"] = escape_value(compiled_requirements) + template_list["results"] = escape_value(compiled_results) + + // -- While we're here, generate an icon of the bowl -- + var/image/compiled_image = image(icon = soup_icon, icon_state = soup_icon_state) + upload_icon(getFlatIcon(compiled_image, no_anim = TRUE), filename) + + // -- Cleanup -- + qdel(soup_recipe) + + // -- All done, apply the template -- + output += include_template("Autowiki/SoupRecipeTemplate", template_list) + + // All that gets wrapped in another template which formats it into a table + return include_template("Autowiki/SoupRecipeTableTemplate", list("content" = output)) diff --git a/code/modules/autowiki/pages/stockparts.dm b/code/modules/autowiki/pages/stockparts.dm new file mode 100644 index 000000000000..fd92ecfaef47 --- /dev/null +++ b/code/modules/autowiki/pages/stockparts.dm @@ -0,0 +1,89 @@ +/// Automtically generated string list of stock part templates and relevant data for the /tg/station wiki +/datum/autowiki/stock_parts + page = "Template:Autowiki/Content/StockParts" + + var/list/battery_whitelist = list( + /obj/item/stock_parts/cell, + /obj/item/stock_parts/cell/high, + /obj/item/stock_parts/cell/super, + /obj/item/stock_parts/cell/hyper, + /obj/item/stock_parts/cell/bluespace, + ) + +/datum/autowiki/stock_parts/generate() + var/output = "" + + for(var/part_type in subtypesof(/obj/item/stock_parts)) + var/obj/item/stock_parts/type_to_check = part_type + if(initial(type_to_check.abstract_type) == part_type) + continue + + if(!battery_whitelist.Find(part_type) && ispath(part_type, /obj/item/stock_parts/cell)) + continue + + var/obj/item/stock_parts/stock_part = new part_type() + + var/datum/design/recipe = find_design(stock_part) + + if(!recipe) + continue + + var/datum/techweb_node/required_node = find_research(recipe) + + var/list/entry_contents = list() + + entry_contents["name"] = escape_value(format_text(stock_part.name)) + entry_contents["icon"] = escape_value(format_text(create_icon(stock_part))) + entry_contents["desc"] = escape_value(format_text(stock_part.desc)) + entry_contents["tier"] = escape_value(format_text("[stock_part.rating]")) + entry_contents["sources"] = escape_value(format_text(generate_source_list(recipe))) + entry_contents["node"] = escape_value(format_text(required_node.display_name)) + entry_contents["materials"] = escape_value(format_text(generate_material_list(recipe))) + + output += include_template("Autowiki/StockPart", entry_contents) + + return output + +/datum/autowiki/stock_parts/proc/find_design(obj/item/stock_parts/stock_part) + for(var/design_type in subtypesof(/datum/design)) + var/datum/design/recipe = new design_type() + + if(ispath(recipe.build_path, stock_part.type)) + return recipe + +/datum/autowiki/stock_parts/proc/find_research(datum/design/recipe) + for(var/node_type in subtypesof(/datum/techweb_node)) + var/datum/techweb_node/node = new node_type() + + if(node.design_ids.Find(recipe.id)) + return node + +/datum/autowiki/stock_parts/proc/create_icon(obj/item/stock_parts/stock_part) + var/filename = SANITIZE_FILENAME(escape_value(stock_part.icon_state)) + upload_icon(icon(stock_part.icon, stock_part.icon_state, SOUTH, 1, FALSE), filename) + + return "Autowiki-[filename].png" + +/datum/autowiki/stock_parts/proc/generate_source_list(datum/design/recipe) + var/list/source_list = list() + + if(recipe.build_type & PROTOLATHE) + source_list.Add("Protolathe") + + if(recipe.build_type & AWAY_LATHE) + source_list.Add("Ancient Protolathe") + + if(recipe.build_type & AUTOLATHE) + source_list.Add("Autolathe") + + return source_list.Join(", ") + +/datum/autowiki/stock_parts/proc/generate_material_list(datum/design/recipe) + var/list/materials = list() + + for(var/ingredient_type in recipe.materials) + var/datum/material/ingredient = new ingredient_type() + + materials += "[recipe.materials[ingredient_type]] [ingredient.name]" + + return materials.Join("
    ") diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm new file mode 100644 index 000000000000..6198e4645eb0 --- /dev/null +++ b/code/modules/autowiki/pages/techweb.dm @@ -0,0 +1,68 @@ +/datum/autowiki/techweb + page = "Template:Autowiki/Content/Techweb" + +/datum/autowiki/techweb/generate() + var/output = "" + + for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) + var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] + if (!node.show_on_wiki) + continue + + if (!valid_node(node)) + continue + + output += "\n\n" + include_template("Autowiki/TechwebEntry", list( + "name" = escape_value(node.display_name), + "description" = escape_value(node.description), + "prerequisites" = generate_prerequisites(node.prereq_ids), + "designs" = generate_designs(node.design_ids), + )) + + return output + +/datum/autowiki/techweb/proc/valid_node(datum/techweb_node/node) + return !node.experimental + +/datum/autowiki/techweb/proc/generate_designs(list/design_ids) + var/output = "" + + for (var/design_id in design_ids) + var/datum/design/design = SSresearch.techweb_designs[design_id] + output += include_template("Autowiki/TechwebEntryDesign", list( + "name" = escape_value(design.name), + "description" = escape_value(design.get_description()), + )) + + return output + +/datum/autowiki/techweb/proc/generate_prerequisites(list/prereq_ids) + var/output = "" + + for (var/prereq_id in prereq_ids) + var/datum/techweb_node/node = SSresearch.techweb_nodes[prereq_id] + output += include_template("Autowiki/TechwebEntryPrerequisite", list( + "name" = escape_value(node.display_name), + )) + + return output + +/datum/autowiki/techweb/experimental + page = "Template:Autowiki/Content/Techweb/Experimental" + +/datum/autowiki/techweb/experimental/valid_node(datum/techweb_node/node) + return node.experimental + +/proc/sort_research_nodes(node_id_a, node_id_b) + var/datum/techweb_node/node_a = SSresearch.techweb_nodes[node_id_a] + var/datum/techweb_node/node_b = SSresearch.techweb_nodes[node_id_b] + + var/prereq_difference = node_a.prereq_ids.len - node_b.prereq_ids.len + if (prereq_difference != 0) + return prereq_difference + + var/experiment_difference = node_a.required_experiments.len - node_b.required_experiments.len + if (experiment_difference != 0) + return experiment_difference + + return sorttext(node_b.display_name, node_a.display_name) diff --git a/code/modules/autowiki/pages/vending.dm b/code/modules/autowiki/pages/vending.dm new file mode 100644 index 000000000000..0a8dd3db0a9d --- /dev/null +++ b/code/modules/autowiki/pages/vending.dm @@ -0,0 +1,56 @@ +/datum/autowiki/vending + page = "Template:Autowiki/Content/VendingMachines" + +/datum/autowiki/vending/generate() + var/output = "" + + var/list/cached_products = list() + + // `powered()` checks if its in a null loc to say it's not powered. + // So we put it inside, something + var/obj/parent = new + + for (var/vending_type in sort_list(subtypesof(/obj/machinery/vending), GLOBAL_PROC_REF(cmp_typepaths_asc))) + var/obj/machinery/vending/vending_machine = new vending_type(parent) + vending_machine.use_power = FALSE + vending_machine.update_icon(UPDATE_ICON_STATE) + + // Technically won't match if product amounts change, but this isn't likely + var/products_cache_key = vending_machine.products.Join("-") + "&" + vending_machine.contraband.Join("-") + "&" + vending_machine.premium.Join("-") + + // In the future, this should show all vending machines that have the same products + if (products_cache_key in cached_products) + qdel(vending_machine) + continue + + cached_products += products_cache_key + + var/filename = SANITIZE_FILENAME(escape_value(format_text(vending_machine.name))) + + output += include_template("Autowiki/VendingMachine", list( + "icon" = escape_value(filename), + "name" = escape_value(format_text(vending_machine.name)), + "products" = format_product_list(vending_machine.products), + "contraband" = format_product_list(vending_machine.contraband), + "premium" = format_product_list(vending_machine.premium), + )) + + // It would be cool to make this support gifs someday, but not now + upload_icon(getFlatIcon(vending_machine, no_anim = TRUE), filename) + + qdel(vending_machine) + + qdel(parent) + + return output + +/datum/autowiki/vending/proc/format_product_list(list/product_list) + var/output = "" + + for (var/obj/product_path as anything in product_list) + output += include_template("Autowiki/VendingMachineProduct", list( + "name" = escape_value(capitalize(format_text(initial(product_path.name)))), + "amount" = product_list[product_path], + )) + + return output diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index c758688221dd..24a57ed44bc6 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -22,7 +22,7 @@ other types of metals and chemistry for reagents). /datum/design //Datum for object designs, used in construction var/name = "Name" //Name of the created object. - var/desc = "Desc" //Description of the created object. + var/desc = null //Description of the created object. var/id = DESIGN_ID_IGNORE //ID of the created object for easy refernece. Alphanumeric, lower-case, no symbols var/build_type = null //Flag as to what kind machine the design is built in. See defines. var/list/materials = list() //List of materials. Format: "id" = amount. @@ -67,6 +67,12 @@ other types of metals and chemistry for reagents). sheet.send(user) return sheet.icon_tag(id) +/// Returns the description of the design +/datum/design/proc/get_description() + var/obj/object_build_item_path = build_path + + return isnull(desc) ? initial(object_build_item_path.desc) : desc + //////////////////////////////////////// //Disks for transporting design datums// //////////////////////////////////////// diff --git a/code/modules/research/techweb/_techweb_node.dm b/code/modules/research/techweb/_techweb_node.dm index 5bf1cff4a57c..00c39591787b 100644 --- a/code/modules/research/techweb/_techweb_node.dm +++ b/code/modules/research/techweb/_techweb_node.dm @@ -18,11 +18,15 @@ var/ui_x = 805 // It's location - override this in techweb_layout.dm var/ui_y = 805 + /// Whether or not this node should show on the wiki + var/show_on_wiki = TRUE + /datum/techweb_node/error_node id = "ERROR" display_name = "ERROR" description = "This usually means something in the database has corrupted. If it doesn't go away automatically, inform Central Command for their techs to fix it ASAP(tm)" - + show_on_wiki = FALSE + /datum/techweb_node/proc/Initialize() //Make lists associative for lookup for(var/id in prereq_ids) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 8b1a6e8f7ddd..7bb0cf189ed4 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -89,6 +89,7 @@ #include "timer_sanity.dm" #include "trait_addition_and_removal.dm" #include "unit_test.dm" +#include "autowiki.dm" #undef TEST_ASSERT #undef TEST_ASSERT_EQUAL diff --git a/code/modules/unit_tests/autowiki.dm b/code/modules/unit_tests/autowiki.dm new file mode 100644 index 000000000000..65ec2e228dd2 --- /dev/null +++ b/code/modules/unit_tests/autowiki.dm @@ -0,0 +1,35 @@ +/// Tests that all autowikis generate something without runtiming +/datum/unit_test/autowiki + +/datum/unit_test/autowiki/Run() + TEST_ASSERT(istext(generate_autowiki_output()), "generate_autowiki_output() did not finish successfully!") + +/// Test that `include_template` produces reasonable results +/datum/unit_test/autowiki_include_template + +/datum/unit_test/autowiki_include_template/Run() + var/datum/autowiki/autowiki_api = new + + TEST_ASSERT_EQUAL( \ + autowiki_api.include_template("Template"), \ + "{{Template}}", \ + "Basic template did not format correctly" \ + ) + + TEST_ASSERT_EQUAL( \ + autowiki_api.include_template("Template", list("name" = "Mothblocks")), \ + "{{Template|name=Mothblocks}}", \ + "Template with basic arguments did not format correctly" \ + ) + + TEST_ASSERT_EQUAL( \ + autowiki_api.include_template("Template", list("name" = autowiki_api.escape_value("P|peline"))), \ + "{{Template|name=P{{!}}peline}}", \ + "Template with escaped arguments did not format correctly" \ + ) + + TEST_ASSERT_EQUAL( \ + autowiki_api.include_template("Template", list("food" = list("fruit", "candy"))), \ + "{{Template|food1=fruit|food2=candy}}", \ + "Template with array arguments did not format correctly" \ + ) diff --git a/tools/autowiki/autowiki.js b/tools/autowiki/autowiki.js new file mode 100644 index 000000000000..8b5c5fc9f00a --- /dev/null +++ b/tools/autowiki/autowiki.js @@ -0,0 +1,83 @@ +const fs = require("fs").promises +const MWBot = require("mwbot") + +const { USERNAME, PASSWORD } = process.env + +if (!USERNAME) { + console.error("USERNAME was not set.") + process.exit(1) +} + +if (!PASSWORD) { + console.error("PASSWORD was not set.") + process.exit(1) +} + +const PAGE_EDIT_FILENAME = process.argv[2] + +if (!PAGE_EDIT_FILENAME) { + console.error("No filename specified to edit pages") + process.exit(1) +} + +const FILE_EDIT_FILENAME = process.argv[3] + +if (!FILE_EDIT_FILENAME) { + console.error("No filename specified to edit files") + process.exit(1) +} + +async function main() { + console.log(`Reading from ${PAGE_EDIT_FILENAME}`) + const editFile = await (await fs.readFile(PAGE_EDIT_FILENAME, "utf8")).split("\n") + + console.log(`Logging in as ${USERNAME}`) + + const bot = new MWBot() + + await bot.loginGetEditToken({ + apiUrl: "https://tgstation13.org/wiki/api.php", + username: USERNAME, + password: PASSWORD, + }) + + console.log("Logged in") + + // This is not Promise.all as to not flood with a bunch of traffic at once + for (const editLine of editFile) { + if (editLine.length === 0) { + continue + } + + let { title, text } = JSON.parse(editLine) + text = "This page is automated by Autowiki. Do NOT edit it manually." + text + + console.log(`Editing ${title}...`) + await bot.edit( + title, + text, + `Autowiki edit @ ${ new Date().toISOString() }`, + ) + } + + // Same here + for (const asset of await fs.readdir(FILE_EDIT_FILENAME)) { + const assetPath = `${FILE_EDIT_FILENAME}/${asset}` + const assetName = `Autowiki-${asset}` + + console.log(`Replacing ${assetName}...`) + await bot.upload( + assetName, + assetPath, + `Autowiki upload @ ${ new Date().toISOString() }`, + ).catch(error => { + if (error.code === "fileexists-no-change") { + console.log(`${assetName} is an exact duplicate`) + } else { + return Promise.reject(error) + } + }) + } +} + +main().catch(console.error) diff --git a/tools/autowiki/package-lock.json b/tools/autowiki/package-lock.json new file mode 100644 index 000000000000..ab2b4493025e --- /dev/null +++ b/tools/autowiki/package-lock.json @@ -0,0 +1,1043 @@ +{ + "name": "autowiki", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "autowiki", + "version": "1.0.0", + "dependencies": { + "mwbot": "^2.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mwbot": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mwbot/-/mwbot-2.0.0.tgz", + "integrity": "sha512-9iTx8oFMntC60yyaPJjN4GEgiQlal7i03jATu7kq5b9BGW5aNz7YbrpjaciLNr0Z33PTdQe0hRTJ0JdUJi2WQg==", + "dependencies": { + "bluebird": "^3.7.2", + "request": "^2.88.2", + "semlog": "^0.6.10", + "semver": "7.3.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/prettyjson": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.5.tgz", + "integrity": "sha512-rksPWtoZb2ZpT5OVgtmy0KHVM+Dca3iVwWY9ifwhcexfjebtgjg3wmrUt9PvJ59XIYBcknQeYHD8IAnVlh9lAw==", + "dependencies": { + "colors": "1.4.0", + "minimist": "^1.2.0" + }, + "bin": { + "prettyjson": "bin/prettyjson" + } + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semlog": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/semlog/-/semlog-0.6.10.tgz", + "integrity": "sha1-DyJa6o6zwvJM6TWNhnjQ9Bp/4Fs=", + "dependencies": { + "chalk": "^1.1.3", + "prettyjson": "^1.1.3" + } + }, + "node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + }, + "mwbot": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mwbot/-/mwbot-2.0.0.tgz", + "integrity": "sha512-9iTx8oFMntC60yyaPJjN4GEgiQlal7i03jATu7kq5b9BGW5aNz7YbrpjaciLNr0Z33PTdQe0hRTJ0JdUJi2WQg==", + "requires": { + "bluebird": "^3.7.2", + "request": "^2.88.2", + "semlog": "^0.6.10", + "semver": "7.3.4" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "prettyjson": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.5.tgz", + "integrity": "sha512-rksPWtoZb2ZpT5OVgtmy0KHVM+Dca3iVwWY9ifwhcexfjebtgjg3wmrUt9PvJ59XIYBcknQeYHD8IAnVlh9lAw==", + "requires": { + "colors": "1.4.0", + "minimist": "^1.2.0" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semlog": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/semlog/-/semlog-0.6.10.tgz", + "integrity": "sha1-DyJa6o6zwvJM6TWNhnjQ9Bp/4Fs=", + "requires": { + "chalk": "^1.1.3", + "prettyjson": "^1.1.3" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/tools/autowiki/package.json b/tools/autowiki/package.json new file mode 100644 index 000000000000..724acf44c13d --- /dev/null +++ b/tools/autowiki/package.json @@ -0,0 +1,10 @@ +{ + "name": "autowiki", + "version": "1.0.0", + "description": "Automatically publish generated pages to the tg wiki", + "main": "autowiki.js", + "author": "Mothblocks", + "dependencies": { + "mwbot": "^2.0.0" + } +} From 8fdd8e1f0c140de497ea41c89143ad2942262c48 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 12 Aug 2024 09:02:34 -0400 Subject: [PATCH 02/18] strange --- .github/workflows/autowiki.yml | 2 +- yogstation.dme | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml index 740b5d7d9eb2..4c06bedd0b2f 100644 --- a/.github/workflows/autowiki.yml +++ b/.github/workflows/autowiki.yml @@ -8,7 +8,7 @@ permissions: jobs: autowiki: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - name: "Check for AUTOWIKI_USERNAME" id: secrets_set diff --git a/yogstation.dme b/yogstation.dme index aff0034c225c..59cd9fdbbfe4 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4432,6 +4432,8 @@ #include "yogstation\code\modules\jungleland\megafauna\tar_king.dm" #include "yogstation\code\modules\language\darkspeak.dm" #include "yogstation\code\modules\language\japanese.dm" +#include "yogstation\code\modules\language\language_holder.dm" +#include "yogstation\code\modules\language\voxpidgin.dm" #include "yogstation\code\modules\liquids\drains.dm" #include "yogstation\code\modules\liquids\height_floors.dm" #include "yogstation\code\modules\liquids\liquid_controller.dm" @@ -4445,8 +4447,6 @@ #include "yogstation\code\modules\liquids\liquid_status_effect.dm" #include "yogstation\code\modules\liquids\liquid_turf.dm" #include "yogstation\code\modules\liquids\tools.dm" -#include "yogstation\code\modules\language\language_holder.dm" -#include "yogstation\code\modules\language\voxpidgin.dm" #include "yogstation\code\modules\mentor\follow.dm" #include "yogstation\code\modules\mentor\mentor.dm" #include "yogstation\code\modules\mentor\mentor_memo.dm" From 02e3d00fa3d8cfa3d2e435240f432d8cfdc062bc Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 12 Aug 2024 09:17:47 -0400 Subject: [PATCH 03/18] fucking dream demon, always not applying files --- yogstation.dme | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/yogstation.dme b/yogstation.dme index 59cd9fdbbfe4..2954aab919a9 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2169,6 +2169,12 @@ #include "code\modules\atmospherics\machinery\portable\portable_atmospherics.dm" #include "code\modules\atmospherics\machinery\portable\pump.dm" #include "code\modules\atmospherics\machinery\portable\scrubber.dm" +#include "code\modules\autowiki\autowiki.dm" +#include "code\modules\autowiki\pages\base.dm" +#include "code\modules\autowiki\pages\soup.dm" +#include "code\modules\autowiki\pages\stockparts.dm" +#include "code\modules\autowiki\pages\techweb.dm" +#include "code\modules\autowiki\pages\vending.dm" #include "code\modules\awaymissions\away_props.dm" #include "code\modules\awaymissions\bluespaceartillery.dm" #include "code\modules\awaymissions\capture_the_flag.dm" From 762f05163da8198653d8a4fc239531ea5b1882af Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Thu, 15 Aug 2024 14:32:44 -0400 Subject: [PATCH 04/18] canning to work on other ports --- .../controllers/configuration/config_entry.dm | 1 - code/modules/autowiki/pages/soup.dm | 135 ------------------ code/modules/autowiki/pages/stockparts.dm | 3 - code/modules/autowiki/pages/techweb.dm | 2 +- code/modules/research/stock_parts.dm | 9 ++ yogstation.dme | 1 - 6 files changed, 10 insertions(+), 141 deletions(-) delete mode 100644 code/modules/autowiki/pages/soup.dm diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index a4ac922ca779..2c0d74a720a7 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -14,7 +14,6 @@ var/modified = FALSE //set to TRUE if the default has been overridden by a config entry var/deprecated_by //the /datum/config_entry type that supercedes this one - var/protection = NONE var/abstract_type = /datum/config_entry //do not instantiate if type matches this diff --git a/code/modules/autowiki/pages/soup.dm b/code/modules/autowiki/pages/soup.dm deleted file mode 100644 index 75521005d8e8..000000000000 --- a/code/modules/autowiki/pages/soup.dm +++ /dev/null @@ -1,135 +0,0 @@ -/datum/autowiki/soup - page = "Template:Autowiki/Content/SoupRecipes" - -/datum/autowiki/soup/generate() - var/output = "" - - // Since we're here, generate a range icon since that's what is installed in most kitchens - var/obj/machinery/oven/range/range = new() - upload_icon(getFlatIcon(range, no_anim = TRUE), "kitchen_range") - qdel(range) - - // Also generate a soup pot icon, as that's what makes soup - var/obj/item/reagent_containers/cup/soup_pot/soup_pot = new() - upload_icon(getFlatIcon(soup_pot, no_anim = TRUE), "soup_pot") - qdel(soup_pot) - - var/container_for_images = /obj/item/reagent_containers/cup/bowl - - for(var/soup_recipe_type in subtypesof(/datum/chemical_reaction/food/soup)) - var/datum/chemical_reaction/food/soup/soup_recipe = new soup_recipe_type() - // Used to determine what icon is displayed on the wiki - var/soup_icon - var/soup_icon_state - // Used to determine what food types the soup is - var/soup_food_types = NONE - // Used for filename and description of the result - var/result_name - var/result_desc - var/result_tastes - // Solid food item results take priority over reagents for showcasing results - if(soup_recipe.resulting_food_path) - var/obj/item/resulting_food = new soup_recipe.resulting_food_path() - result_name = format_text(resulting_food.name) - result_desc = resulting_food.desc - - soup_icon = resulting_food.icon - soup_icon_state = resulting_food.icon_state - - if(istype(resulting_food, /obj/item/food)) - var/obj/item/food/resulting_food_casted = resulting_food - result_tastes = resulting_food_casted.tastes?.Copy() - soup_food_types = resulting_food_casted.foodtypes || NONE - - qdel(resulting_food) - - // Otherwise, it should be a reagent. - else - var/result_soup_type = soup_recipe.results[1] - var/datum/reagent/result_soup = new result_soup_type() - result_name = format_text(result_soup.name) - result_desc = result_soup.description - result_tastes = result_soup.get_taste_description() - - var/datum/glass_style/has_foodtype/soup_style = GLOB.glass_style_singletons[container_for_images][result_soup_type] - soup_icon = soup_style.icon - soup_icon_state = soup_style.icon_state - soup_food_types = soup_style.drink_type - - qdel(result_soup) - - var/filename = "soup_[SANITIZE_FILENAME(escape_value(result_name))]" - - // -- Compiles a list of required reagents and food items -- - var/list/all_needs_text = list() - for(var/datum/reagent/reagent_type as anything in soup_recipe.required_reagents) - all_needs_text += "[soup_recipe.required_reagents[reagent_type]] units [initial(reagent_type.name)]" - for(var/datum/reagent/reagent_type as anything in soup_recipe.required_catalysts) - all_needs_text += "[soup_recipe.required_catalysts[reagent_type]] units [initial(reagent_type.name)] (not consumed)" - - for(var/obj/item/food_type as anything in soup_recipe.required_ingredients) - var/num_needed = soup_recipe.required_ingredients[food_type] - // Instantiating this so we can do plurality correctly. - // We can use initial but it'll give us stuff like "eyballss". - var/obj/item/food = new food_type() - all_needs_text += "[num_needed] [food.name]\s" - qdel(food) - - all_needs_text += soup_recipe.describe_recipe_details() - all_needs_text += "At temperature [soup_recipe.required_temp]K" - var/compiled_requirements = "" - for(var/req_text in all_needs_text) - if(length(req_text)) - compiled_requirements += "
  • [req_text]
  • " - if(length(compiled_requirements)) - compiled_requirements = "
      [compiled_requirements]
    " - - // -- Compiles a list of resulting reagents -- - var/list/all_results_text = list() - for(var/datum/reagent/reagent_type as anything in soup_recipe.results) - var/num_given = soup_recipe.results[reagent_type] - all_results_text += "[num_given] units [initial(reagent_type.name)]" - if(soup_recipe.resulting_food_path) - all_results_text += "1 [initial(soup_recipe.resulting_food_path.name)]" - - all_results_text += soup_recipe.describe_result() - var/compiled_results = "" - for(var/res_text in all_results_text) - if(length(res_text)) - compiled_results += "
  • [res_text]
  • " - if(length(compiled_results)) - compiled_results = "
      [compiled_results]
    " - - // -- Assemble the template list -- - var/list/template_list = list() - if(istype(soup_recipe, /datum/chemical_reaction/food/soup/custom)) - // Painful snowflaking here for custom recipes, - // but because they default to "bowl of water" we can't let it generate fully on its own. - template_list["name"] = "Custom Soup" - template_list["taste"] = "Whatever you use." - template_list["foodtypes"] = "Whatever you use." - template_list["description"] = "A custom soup recipe, allowing you to throw whatever you want in the pot." - - else - var/foodtypes_readable = jointext(bitfield_to_list(soup_food_types, FOOD_FLAGS_IC), ", ") || "None" - template_list["name"] = escape_value(result_name) - template_list["taste"] = escape_value(length(result_tastes) ? capitalize(jointext(result_tastes, ", ")) : "No taste") - template_list["foodtypes"] = escape_value(foodtypes_readable) - template_list["description"] = escape_value(result_desc) - - template_list["icon"] = escape_value(filename) - template_list["requirements"] = escape_value(compiled_requirements) - template_list["results"] = escape_value(compiled_results) - - // -- While we're here, generate an icon of the bowl -- - var/image/compiled_image = image(icon = soup_icon, icon_state = soup_icon_state) - upload_icon(getFlatIcon(compiled_image, no_anim = TRUE), filename) - - // -- Cleanup -- - qdel(soup_recipe) - - // -- All done, apply the template -- - output += include_template("Autowiki/SoupRecipeTemplate", template_list) - - // All that gets wrapped in another template which formats it into a table - return include_template("Autowiki/SoupRecipeTableTemplate", list("content" = output)) diff --git a/code/modules/autowiki/pages/stockparts.dm b/code/modules/autowiki/pages/stockparts.dm index fd92ecfaef47..69db16d94581 100644 --- a/code/modules/autowiki/pages/stockparts.dm +++ b/code/modules/autowiki/pages/stockparts.dm @@ -70,9 +70,6 @@ if(recipe.build_type & PROTOLATHE) source_list.Add("Protolathe") - if(recipe.build_type & AWAY_LATHE) - source_list.Add("Ancient Protolathe") - if(recipe.build_type & AUTOLATHE) source_list.Add("Autolathe") diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm index 6198e4645eb0..83525621b548 100644 --- a/code/modules/autowiki/pages/techweb.dm +++ b/code/modules/autowiki/pages/techweb.dm @@ -4,7 +4,7 @@ /datum/autowiki/techweb/generate() var/output = "" - for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) + for (var/node_id in sort_list(SSresearch.techweb_nodes, /proc/sort_research_nodes)) var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] if (!node.show_on_wiki) continue diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 6a28673101e9..ce66fdb8fb40 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -13,6 +13,10 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi var/works_from_distance = FALSE var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/rped.ogg' var/alt_sound = null + + ///The generic category type that the stock part belongs to. Generic objects that should not be instantiated should have the same type and abstract_type + var/abstract_type = /obj/item/stock_parts + /obj/item/storage/part_replacer/pre_attack(obj/machinery/T, mob/living/user, params) if(!istype(T) || (!T.component_parts && !T.works_with_rped_anyways)) @@ -290,6 +294,11 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi // Subspace stock parts +/obj/item/stock_parts/subspace + name = "subspace stock part" + desc = "What?" + abstract_type = /obj/item/stock_parts/subspace + /obj/item/stock_parts/subspace/ansible name = "subspace ansible" icon_state = "subspace_ansible" diff --git a/yogstation.dme b/yogstation.dme index 2954aab919a9..eead7d5ef77b 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2171,7 +2171,6 @@ #include "code\modules\atmospherics\machinery\portable\scrubber.dm" #include "code\modules\autowiki\autowiki.dm" #include "code\modules\autowiki\pages\base.dm" -#include "code\modules\autowiki\pages\soup.dm" #include "code\modules\autowiki\pages\stockparts.dm" #include "code\modules\autowiki\pages\techweb.dm" #include "code\modules\autowiki\pages\vending.dm" From dacb3c24361b3b88b6253b59aec5c52bf1a5f9f5 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Tue, 20 Aug 2024 03:25:38 -0400 Subject: [PATCH 05/18] found the problem --- code/modules/autowiki/pages/techweb.dm | 5 +++++ code/modules/research/stock_parts.dm | 5 ++--- yogstation.dme | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm index 83525621b548..7212b5765caa 100644 --- a/code/modules/autowiki/pages/techweb.dm +++ b/code/modules/autowiki/pages/techweb.dm @@ -1,3 +1,8 @@ +//NOTICE: +//not enabled due to our system. come back to rework to reflect or modernize our research system +//remove this if completed + + /datum/autowiki/techweb page = "Template:Autowiki/Content/Techweb" diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index ce66fdb8fb40..72f6951a7e6f 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -13,9 +13,6 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi var/works_from_distance = FALSE var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/rped.ogg' var/alt_sound = null - - ///The generic category type that the stock part belongs to. Generic objects that should not be instantiated should have the same type and abstract_type - var/abstract_type = /obj/item/stock_parts /obj/item/storage/part_replacer/pre_attack(obj/machinery/T, mob/living/user, params) @@ -129,6 +126,8 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi icon = 'icons/obj/stock_parts.dmi' w_class = WEIGHT_CLASS_SMALL var/rating = 1 + ///The generic category type that the stock part belongs to. Generic objects that should not be instantiated should have the same type and abstract_type + var/abstract_type = /obj/item/stock_parts /obj/item/stock_parts/Initialize(mapload) . = ..() diff --git a/yogstation.dme b/yogstation.dme index eead7d5ef77b..cefc45dd3546 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2172,7 +2172,6 @@ #include "code\modules\autowiki\autowiki.dm" #include "code\modules\autowiki\pages\base.dm" #include "code\modules\autowiki\pages\stockparts.dm" -#include "code\modules\autowiki\pages\techweb.dm" #include "code\modules\autowiki\pages\vending.dm" #include "code\modules\awaymissions\away_props.dm" #include "code\modules\awaymissions\bluespaceartillery.dm" From e1d556c2b3b6f7a0a8c694d46b17fd4bae05b918 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Tue, 20 Aug 2024 21:38:27 -0400 Subject: [PATCH 06/18] please be happy --- yogstation.dme | 1 - 1 file changed, 1 deletion(-) diff --git a/yogstation.dme b/yogstation.dme index cefc45dd3546..9fd34fbf7389 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2171,7 +2171,6 @@ #include "code\modules\atmospherics\machinery\portable\scrubber.dm" #include "code\modules\autowiki\autowiki.dm" #include "code\modules\autowiki\pages\base.dm" -#include "code\modules\autowiki\pages\stockparts.dm" #include "code\modules\autowiki\pages\vending.dm" #include "code\modules\awaymissions\away_props.dm" #include "code\modules\awaymissions\bluespaceartillery.dm" From 7e684aa559da288eb4bb8790a455be6f9297e417 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Tue, 27 Aug 2024 23:10:27 -0400 Subject: [PATCH 07/18] lets see --- tools/autowiki/autowiki.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/autowiki/autowiki.js b/tools/autowiki/autowiki.js index 8b5c5fc9f00a..00d86942b56d 100644 --- a/tools/autowiki/autowiki.js +++ b/tools/autowiki/autowiki.js @@ -36,7 +36,7 @@ async function main() { const bot = new MWBot() await bot.loginGetEditToken({ - apiUrl: "https://tgstation13.org/wiki/api.php", + apiUrl: "https://wiki.yogstation.net/wiki/api.php", username: USERNAME, password: PASSWORD, }) From 86e54ded36c9337b7c11f6f7b3477775ed90ec15 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Tue, 27 Aug 2024 23:38:02 -0400 Subject: [PATCH 08/18] wrong link --- tools/autowiki/autowiki.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/autowiki/autowiki.js b/tools/autowiki/autowiki.js index 00d86942b56d..f2dbbdf3e91b 100644 --- a/tools/autowiki/autowiki.js +++ b/tools/autowiki/autowiki.js @@ -36,7 +36,7 @@ async function main() { const bot = new MWBot() await bot.loginGetEditToken({ - apiUrl: "https://wiki.yogstation.net/wiki/api.php", + apiUrl: "https://wiki.yogstation.net/api.php", username: USERNAME, password: PASSWORD, }) From d5bbe3784d03360ba05fccbdd334a430b42c3dbe Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 2 Sep 2024 00:48:40 -0400 Subject: [PATCH 09/18] cutting bloat --- code/modules/autowiki/pages/stockparts.dm | 86 ----------------------- code/modules/autowiki/pages/techweb.dm | 73 ------------------- 2 files changed, 159 deletions(-) delete mode 100644 code/modules/autowiki/pages/stockparts.dm delete mode 100644 code/modules/autowiki/pages/techweb.dm diff --git a/code/modules/autowiki/pages/stockparts.dm b/code/modules/autowiki/pages/stockparts.dm deleted file mode 100644 index 69db16d94581..000000000000 --- a/code/modules/autowiki/pages/stockparts.dm +++ /dev/null @@ -1,86 +0,0 @@ -/// Automtically generated string list of stock part templates and relevant data for the /tg/station wiki -/datum/autowiki/stock_parts - page = "Template:Autowiki/Content/StockParts" - - var/list/battery_whitelist = list( - /obj/item/stock_parts/cell, - /obj/item/stock_parts/cell/high, - /obj/item/stock_parts/cell/super, - /obj/item/stock_parts/cell/hyper, - /obj/item/stock_parts/cell/bluespace, - ) - -/datum/autowiki/stock_parts/generate() - var/output = "" - - for(var/part_type in subtypesof(/obj/item/stock_parts)) - var/obj/item/stock_parts/type_to_check = part_type - if(initial(type_to_check.abstract_type) == part_type) - continue - - if(!battery_whitelist.Find(part_type) && ispath(part_type, /obj/item/stock_parts/cell)) - continue - - var/obj/item/stock_parts/stock_part = new part_type() - - var/datum/design/recipe = find_design(stock_part) - - if(!recipe) - continue - - var/datum/techweb_node/required_node = find_research(recipe) - - var/list/entry_contents = list() - - entry_contents["name"] = escape_value(format_text(stock_part.name)) - entry_contents["icon"] = escape_value(format_text(create_icon(stock_part))) - entry_contents["desc"] = escape_value(format_text(stock_part.desc)) - entry_contents["tier"] = escape_value(format_text("[stock_part.rating]")) - entry_contents["sources"] = escape_value(format_text(generate_source_list(recipe))) - entry_contents["node"] = escape_value(format_text(required_node.display_name)) - entry_contents["materials"] = escape_value(format_text(generate_material_list(recipe))) - - output += include_template("Autowiki/StockPart", entry_contents) - - return output - -/datum/autowiki/stock_parts/proc/find_design(obj/item/stock_parts/stock_part) - for(var/design_type in subtypesof(/datum/design)) - var/datum/design/recipe = new design_type() - - if(ispath(recipe.build_path, stock_part.type)) - return recipe - -/datum/autowiki/stock_parts/proc/find_research(datum/design/recipe) - for(var/node_type in subtypesof(/datum/techweb_node)) - var/datum/techweb_node/node = new node_type() - - if(node.design_ids.Find(recipe.id)) - return node - -/datum/autowiki/stock_parts/proc/create_icon(obj/item/stock_parts/stock_part) - var/filename = SANITIZE_FILENAME(escape_value(stock_part.icon_state)) - upload_icon(icon(stock_part.icon, stock_part.icon_state, SOUTH, 1, FALSE), filename) - - return "Autowiki-[filename].png" - -/datum/autowiki/stock_parts/proc/generate_source_list(datum/design/recipe) - var/list/source_list = list() - - if(recipe.build_type & PROTOLATHE) - source_list.Add("Protolathe") - - if(recipe.build_type & AUTOLATHE) - source_list.Add("Autolathe") - - return source_list.Join(", ") - -/datum/autowiki/stock_parts/proc/generate_material_list(datum/design/recipe) - var/list/materials = list() - - for(var/ingredient_type in recipe.materials) - var/datum/material/ingredient = new ingredient_type() - - materials += "[recipe.materials[ingredient_type]] [ingredient.name]" - - return materials.Join("
    ") diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm deleted file mode 100644 index 7212b5765caa..000000000000 --- a/code/modules/autowiki/pages/techweb.dm +++ /dev/null @@ -1,73 +0,0 @@ -//NOTICE: -//not enabled due to our system. come back to rework to reflect or modernize our research system -//remove this if completed - - -/datum/autowiki/techweb - page = "Template:Autowiki/Content/Techweb" - -/datum/autowiki/techweb/generate() - var/output = "" - - for (var/node_id in sort_list(SSresearch.techweb_nodes, /proc/sort_research_nodes)) - var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] - if (!node.show_on_wiki) - continue - - if (!valid_node(node)) - continue - - output += "\n\n" + include_template("Autowiki/TechwebEntry", list( - "name" = escape_value(node.display_name), - "description" = escape_value(node.description), - "prerequisites" = generate_prerequisites(node.prereq_ids), - "designs" = generate_designs(node.design_ids), - )) - - return output - -/datum/autowiki/techweb/proc/valid_node(datum/techweb_node/node) - return !node.experimental - -/datum/autowiki/techweb/proc/generate_designs(list/design_ids) - var/output = "" - - for (var/design_id in design_ids) - var/datum/design/design = SSresearch.techweb_designs[design_id] - output += include_template("Autowiki/TechwebEntryDesign", list( - "name" = escape_value(design.name), - "description" = escape_value(design.get_description()), - )) - - return output - -/datum/autowiki/techweb/proc/generate_prerequisites(list/prereq_ids) - var/output = "" - - for (var/prereq_id in prereq_ids) - var/datum/techweb_node/node = SSresearch.techweb_nodes[prereq_id] - output += include_template("Autowiki/TechwebEntryPrerequisite", list( - "name" = escape_value(node.display_name), - )) - - return output - -/datum/autowiki/techweb/experimental - page = "Template:Autowiki/Content/Techweb/Experimental" - -/datum/autowiki/techweb/experimental/valid_node(datum/techweb_node/node) - return node.experimental - -/proc/sort_research_nodes(node_id_a, node_id_b) - var/datum/techweb_node/node_a = SSresearch.techweb_nodes[node_id_a] - var/datum/techweb_node/node_b = SSresearch.techweb_nodes[node_id_b] - - var/prereq_difference = node_a.prereq_ids.len - node_b.prereq_ids.len - if (prereq_difference != 0) - return prereq_difference - - var/experiment_difference = node_a.required_experiments.len - node_b.required_experiments.len - if (experiment_difference != 0) - return experiment_difference - - return sorttext(node_b.display_name, node_a.display_name) From 0608d8a7501f887b4dcd156127291ebf3f96affb Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Tue, 17 Sep 2024 17:54:34 -0400 Subject: [PATCH 10/18] happy? --- code/modules/autowiki/pages/techweb.dm | 52 ++++++++++++++++++++++++++ yogstation.dme | 1 + 2 files changed, 53 insertions(+) create mode 100644 code/modules/autowiki/pages/techweb.dm diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm new file mode 100644 index 000000000000..882b275a2860 --- /dev/null +++ b/code/modules/autowiki/pages/techweb.dm @@ -0,0 +1,52 @@ +/datum/autowiki/techweb + page = "Template:Autowiki/Content/TechWeb" + +/datum/autowiki/techweb/generate() + var/output = "" + + for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) + var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] + if (!node.show_on_wiki) + continue + + output += "\n\n" + include_template("Autowiki/TechwebEntry", list( + "name" = escape_value(node.display_name), + "description" = escape_value(node.description), + "prerequisites" = generate_prerequisites(node.prereq_ids), + "designs" = generate_designs(node.design_ids), + )) + + return output + +/datum/autowiki/techweb/proc/generate_designs(list/design_ids) + var/output = "" + + for (var/design_id in design_ids) + var/datum/design/design = SSresearch.techweb_designs[design_id] + output += include_template("Autowiki/TechwebEntryDesign", list( + "name" = escape_value(design.name), + "description" = escape_value(design.get_description()), + )) + + return output + +/datum/autowiki/techweb/proc/generate_prerequisites(list/prereq_ids) + var/output = "" + + for (var/prereq_id in prereq_ids) + var/datum/techweb_node/node = SSresearch.techweb_nodes[prereq_id] + output += include_template("Autowiki/TechwebEntryPrerequisite", list( + "name" = escape_value(node.display_name), + )) + + return output + +/proc/sort_research_nodes(node_id_a, node_id_b) + var/datum/techweb_node/node_a = SSresearch.techweb_nodes[node_id_a] + var/datum/techweb_node/node_b = SSresearch.techweb_nodes[node_id_b] + + var/prereq_difference = node_a.prereq_ids.len - node_b.prereq_ids.len + if (prereq_difference != 0) + return prereq_difference + + return sorttext(node_b.display_name, node_a.display_name) diff --git a/yogstation.dme b/yogstation.dme index 89c76a118c1d..ce8d4b2bcbe5 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2172,6 +2172,7 @@ #include "code\modules\atmospherics\machinery\portable\scrubber.dm" #include "code\modules\autowiki\autowiki.dm" #include "code\modules\autowiki\pages\base.dm" +#include "code\modules\autowiki\pages\techweb.dm" #include "code\modules\autowiki\pages\vending.dm" #include "code\modules\awaymissions\away_props.dm" #include "code\modules\awaymissions\bluespaceartillery.dm" From e430cdda8693edd41ca889ec04577badd227d14b Mon Sep 17 00:00:00 2001 From: wonderinghost <88801435+wonderinghost@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:23:01 -0400 Subject: [PATCH 11/18] Update mech_fabricator.dm --- code/game/mecha/mech_fabricator.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 6fe6fe243123..f4217a799c79 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -272,7 +272,7 @@ /** * Generates a list of resources / materials available to this Exosuit Fab * - * Returns null if there is no material container available.B + * Returns null if there is no material container available. * List format is list(material_name = list(amount = ..., ref = ..., etc.)) */ /obj/machinery/mecha_part_fabricator/proc/output_available_resources() From cd35f28ec28176bdd9eeb935e675f50738983399 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 30 Sep 2024 01:26:42 -0400 Subject: [PATCH 12/18] most likely broken time to check --- code/modules/autowiki/pages/techweb.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm index 882b275a2860..709de1e6d60e 100644 --- a/code/modules/autowiki/pages/techweb.dm +++ b/code/modules/autowiki/pages/techweb.dm @@ -3,19 +3,22 @@ /datum/autowiki/techweb/generate() var/output = "" - + var/datum/asset/spritesheet/research = get_asset_datum(/datum/asset/spritesheet/research_designs) + var/filename = SANITIZE_FILENAME(escape_value(format_text(research))) for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] if (!node.show_on_wiki) continue output += "\n\n" + include_template("Autowiki/TechwebEntry", list( + "icon" = (filename), "name" = escape_value(node.display_name), "description" = escape_value(node.description), "prerequisites" = generate_prerequisites(node.prereq_ids), "designs" = generate_designs(node.design_ids), )) + upload_icon(getFlatIcon(research, no_anim = TRUE), filename) return output /datum/autowiki/techweb/proc/generate_designs(list/design_ids) From 37b19aa88a07e9e9e00f9b1083cf82c5876e0c8c Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 30 Sep 2024 01:33:03 -0400 Subject: [PATCH 13/18] Update _compile_options.dm --- code/_compile_options.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index debcdc1da52a..19934d74a4bd 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -25,7 +25,7 @@ /// If this is uncommented, Autowiki will generate edits and shut down the server. /// Prefer the autowiki build target instead. -// #define AUTOWIKI + #define AUTOWIKI // If defined, we will NOT defer asset generation till later in the game, and will instead do it all at once, during initiialize //#define DO_NOT_DEFER_ASSETS From 56bf037ecc71925988cbad3db69db2e7c565879e Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 30 Sep 2024 01:50:31 -0400 Subject: [PATCH 14/18] not shitting out errors --- code/modules/autowiki/pages/techweb.dm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm index 709de1e6d60e..0c487c953b91 100644 --- a/code/modules/autowiki/pages/techweb.dm +++ b/code/modules/autowiki/pages/techweb.dm @@ -3,8 +3,10 @@ /datum/autowiki/techweb/generate() var/output = "" + // should be the the item icon we are trying to upload var/datum/asset/spritesheet/research = get_asset_datum(/datum/asset/spritesheet/research_designs) - var/filename = SANITIZE_FILENAME(escape_value(format_text(research))) + // filenames is the name of the icon file + var/filename = "researchables" for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] if (!node.show_on_wiki) From 3a7526b5a213810a3807d03c0a01548803735950 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 30 Sep 2024 01:51:37 -0400 Subject: [PATCH 15/18] oops --- code/_compile_options.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 19934d74a4bd..6dea4d4c6e56 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -25,7 +25,7 @@ /// If this is uncommented, Autowiki will generate edits and shut down the server. /// Prefer the autowiki build target instead. - #define AUTOWIKI + //#define AUTOWIKI // If defined, we will NOT defer asset generation till later in the game, and will instead do it all at once, during initiialize //#define DO_NOT_DEFER_ASSETS From 72d1ec48d8dd8f9eef7ac7ecea9ba9c339e8c9ab Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Mon, 30 Sep 2024 02:09:38 -0400 Subject: [PATCH 16/18] test --- code/modules/autowiki/pages/techweb.dm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm index 0c487c953b91..a8efb7a85014 100644 --- a/code/modules/autowiki/pages/techweb.dm +++ b/code/modules/autowiki/pages/techweb.dm @@ -3,17 +3,19 @@ /datum/autowiki/techweb/generate() var/output = "" + // should be the the item icon we are trying to upload var/datum/asset/spritesheet/research = get_asset_datum(/datum/asset/spritesheet/research_designs) // filenames is the name of the icon file var/filename = "researchables" + for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] if (!node.show_on_wiki) continue output += "\n\n" + include_template("Autowiki/TechwebEntry", list( - "icon" = (filename), + "icon" = escape_value(filename), "name" = escape_value(node.display_name), "description" = escape_value(node.description), "prerequisites" = generate_prerequisites(node.prereq_ids), From 63e40113356cc4d6d71b8f23e939e451e46faf9e Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Fri, 18 Oct 2024 23:34:50 -0400 Subject: [PATCH 17/18] fixed and redundant check --- code/modules/autowiki/pages/base.dm | 4 ++++ code/modules/autowiki/pages/techweb.dm | 8 +++++--- code/modules/autowiki/pages/vending.dm | 7 +++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/code/modules/autowiki/pages/base.dm b/code/modules/autowiki/pages/base.dm index 8e745ace61c2..30a060054f5a 100644 --- a/code/modules/autowiki/pages/base.dm +++ b/code/modules/autowiki/pages/base.dm @@ -45,8 +45,12 @@ // Fuck you if (IsAdminAdvancedProcCall()) return + var/static/uploaded_icons = list() + if(uploaded_icons["[name]"]) + CRASH("We tried uploading an icon, but the name \"[name]\" was already taken!") fcopy(icon, "data/autowiki_files/[name].png") + uploaded_icons["[name]"] = TRUE /// Escape a parameter such that it can be correctly put inside a wiki output /datum/autowiki/proc/escape_value(parameter) diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm index a8efb7a85014..67c80294526e 100644 --- a/code/modules/autowiki/pages/techweb.dm +++ b/code/modules/autowiki/pages/techweb.dm @@ -4,13 +4,15 @@ /datum/autowiki/techweb/generate() var/output = "" - // should be the the item icon we are trying to upload - var/datum/asset/spritesheet/research = get_asset_datum(/datum/asset/spritesheet/research_designs) // filenames is the name of the icon file var/filename = "researchables" for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] + //the images we are trying to upload + var/datum/design/displayed_design = SSresearch.techweb_design_by_id(node.design_ids.len ? node.design_ids[1] : null) + var/research = displayed_design + if (!node.show_on_wiki) continue @@ -22,7 +24,7 @@ "designs" = generate_designs(node.design_ids), )) - upload_icon(getFlatIcon(research, no_anim = TRUE), filename) + upload_icon(getFlatIcon(research, no_anim = TRUE), filename) return output /datum/autowiki/techweb/proc/generate_designs(list/design_ids) diff --git a/code/modules/autowiki/pages/vending.dm b/code/modules/autowiki/pages/vending.dm index 0a8dd3db0a9d..0dcbbf26646e 100644 --- a/code/modules/autowiki/pages/vending.dm +++ b/code/modules/autowiki/pages/vending.dm @@ -10,11 +10,14 @@ // So we put it inside, something var/obj/parent = new - for (var/vending_type in sort_list(subtypesof(/obj/machinery/vending), GLOBAL_PROC_REF(cmp_typepaths_asc))) + for (var/obj/machinery/vending/vending_type as anything in sort_list(subtypesof(/obj/machinery/vending), GLOBAL_PROC_REF(cmp_typepaths_asc))) + var/obj/machinery/vending/parent_machine = type2parent(vending_type) + if(initial(parent_machine.name) == initial(vending_type.name)) + continue //Same name, likely just a slightly touched up subtype for specific maps. var/obj/machinery/vending/vending_machine = new vending_type(parent) vending_machine.use_power = FALSE vending_machine.update_icon(UPDATE_ICON_STATE) - + // Technically won't match if product amounts change, but this isn't likely var/products_cache_key = vending_machine.products.Join("-") + "&" + vending_machine.contraband.Join("-") + "&" + vending_machine.premium.Join("-") From 83fabb675aebb202fdabebd310f3a6053e956df0 Mon Sep 17 00:00:00 2001 From: wonderinghost Date: Sat, 19 Oct 2024 01:14:57 -0400 Subject: [PATCH 18/18] does this break? --- code/modules/autowiki/pages/techweb.dm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/code/modules/autowiki/pages/techweb.dm b/code/modules/autowiki/pages/techweb.dm index 67c80294526e..18c9f3d0f0ad 100644 --- a/code/modules/autowiki/pages/techweb.dm +++ b/code/modules/autowiki/pages/techweb.dm @@ -3,18 +3,20 @@ /datum/autowiki/techweb/generate() var/output = "" - - // filenames is the name of the icon file - var/filename = "researchables" for (var/node_id in sort_list(SSresearch.techweb_nodes, GLOBAL_PROC_REF(sort_research_nodes))) var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] //the images we are trying to upload var/datum/design/displayed_design = SSresearch.techweb_design_by_id(node.design_ids.len ? node.design_ids[1] : null) + var/datum/design/doped_design = displayed_design + if(initial(doped_design.name) == initial(displayed_design.name)) + continue //copy protection var/research = displayed_design - + if (!node.show_on_wiki) continue + // filenames is the name of the icon file + var/filename = SANITIZE_FILENAME(escape_value(format_text(node.display_name))) output += "\n\n" + include_template("Autowiki/TechwebEntry", list( "icon" = escape_value(filename),