Compare commits
439 Commits
wsc-dfc
...
wsc-master
Author | SHA1 | Date |
---|---|---|
cora | a1c54e5f21 | |
cora | ef043544c6 | |
cora | 427cbad41f | |
cora | affad32aa0 | |
cora | 7739cf39d2 | |
cora | c380ab95b6 | |
cora | 1912e3302e | |
cora | 30de6b6b88 | |
cora | cce6e768a8 | |
cora | aab363998d | |
cora | ef0f05c4d2 | |
cora | 9991338895 | |
cora | 17f29e7579 | |
cora | 8884c81f08 | |
cora | b2bf5e5b63 | |
cora | e73d8faf67 | |
cora | 0d6c7da4eb | |
cora | 89df993a45 | |
cora | 8889f0bbff | |
cora | 9b27896259 | |
cora | b031ab6468 | |
cora | cf2eb29a76 | |
cora | 21f8e7e7bf | |
cora | f6b0042989 | |
cora | 2550294514 | |
cora | d7b4931778 | |
cora | 43cd5d2e8d | |
cora | 1541545758 | |
cora | f497a37bee | |
cora | 6abde162d9 | |
cora | 26dda03846 | |
cora | 5b427dd5aa | |
cora | 4b1330c8c3 | |
cora | 45a0a33ba1 | |
cora | 8ca63644e3 | |
cora | 34ca75586e | |
cora | fd05f16dd6 | |
cora | c4810bdb71 | |
cora | a2e4672a53 | |
cora | 34da23941e | |
cora | a0bbcece4c | |
cron | 4f940c2000 | |
cora | 5c00c9ca7f | |
cora | a825bdf8f3 | |
cron | 0953f112e5 | |
cron | 195796b162 | |
cron | c552435c41 | |
cron | 0a3e70374e | |
cora | facc8ad338 | |
cora | 7d43cde6f0 | |
cora | cc1664e650 | |
cron | 3c4d034e88 | |
cora | bc31d696ef | |
cora | a9e888aa0c | |
cron | 5f90569029 | |
cron | ce30691aeb | |
cron | 7855cac461 | |
cron | c4a075add1 | |
cora | 77274845fd | |
cron | 57f10ad0c1 | |
cron | 285b6801a0 | |
cron | 99eec7d996 | |
cron | 6dae48fe85 | |
cron | 48f3d8d2b9 | |
cron | 135fc77230 | |
cora | 9bee7db1c3 | |
cora | 5dbcf42e6e | |
cora | 2b26787634 | |
cora | 87b5f71220 | |
cora | ddfc8c8dae | |
cora | ee5c11894c | |
cora | 4e4d6950cc | |
cora | 7741ad2d7d | |
cora | a4ed213a56 | |
cora | f1fab23f78 | |
cora | 0dac71797c | |
cora | bcdb33f555 | |
cora | b0bad30dc5 | |
cora | 26c66e89be | |
cora | 4fe607d0cf | |
cora | c03ab2f6d9 | |
cron | ceaa9a2874 | |
cron | bae0e18c00 | |
cron | ccefd5d2e7 | |
cron | e9c8661feb | |
cron | 8f600e0405 | |
cron | 30d852cd84 | |
cron | 0febd39537 | |
cron | 6c73180988 | |
cron | f21af5e5a0 | |
cron | b003dd6211 | |
cron | 6a336597a7 | |
cora | 557ea94968 | |
cora | b2ab01cf2f | |
cora | 2d00d16f96 | |
cron | da090876a4 | |
cron | 5bf454f94e | |
cora | 4a40d7daff | |
cron | e05a24b728 | |
cron | 42a253cc71 | |
cora | a4b2aca647 | |
cron | da00f89ab8 | |
cron | 96d6104265 | |
cron | f934733623 | |
cron | 89dbe3dcd6 | |
cora | d8eaf0f8bb | |
cora | aa046ffd13 | |
cora | f62ac54e38 | |
cora | 5bfa7db146 | |
cora | b00f4e42e3 | |
cora | c86f1718f1 | |
cora | c5312c9507 | |
cora | 00dc99516f | |
cora | 5cb9591bb5 | |
cora | ac8683a777 | |
cora | 41c9e86549 | |
cora | d46bf9a1fc | |
cron | 954161bf94 | |
cora | 6006cebc6b | |
cora | 1405194bac | |
cora | b32586700a | |
cora | 1603f86387 | |
cora | 8155cf4ebc | |
cora | 69ba983410 | |
cora | 46c9b4b5b6 | |
cora | 435d82cc57 | |
cora | f956ff8566 | |
cora | 4ea52f350b | |
cora | c65b6a7299 | |
cora | aa945ad80c | |
cora | be1aed758f | |
cora | ca106b1546 | |
cora | 7b0d792a63 | |
cora | e6371af7e7 | |
cora | 4db6bde127 | |
cora | 75e85290cb | |
cora | b4da45df12 | |
cora | 0c5403d06e | |
cora | ef72107c0a | |
cora | bfa5bab2a5 | |
cron | fde02131c8 | |
cora | bc5df968fc | |
cora | 30a14f5874 | |
cora | 773cf760b8 | |
cora | b5ead96d20 | |
cora | 9cf32d9749 | |
cora | 7611e734e0 | |
cora | dc4bd0218c | |
cron | 1cf6ad214e | |
cron | 9f1eca494c | |
cora | 39cf1f197d | |
cora | e5c91a3a22 | |
cron | 2b80dfaa51 | |
cron | 8c5be087f3 | |
cron | 6a5f605fb3 | |
cron | 3d6404566f | |
cron | ff4c79f16d | |
cron | 961a0d3803 | |
cron | ba170c5193 | |
cron | 1cc7f25afd | |
cron | 38629dec56 | |
cron | e7f1106b61 | |
cron | c37a7f5020 | |
cron | f8be6e24e9 | |
cron | 016be0eede | |
cron | 929253e84c | |
cron | 83840da8f8 | |
cora | 17ce7c0fa5 | |
cron | 0ce3485357 | |
cora | ea30789680 | |
cora | 1cb2279eff | |
cora | f985976972 | |
cora | ddb96e465c | |
cora | 8a237b4f1b | |
cron | 5f92bd9746 | |
cron | 85422520b4 | |
cora | 0a95b8b45b | |
cora | 263dbeac47 | |
cron | eeff0d4be0 | |
cron | 14b9c0b98f | |
cora | 2edcfe4992 | |
cora | 93984e27de | |
cora | 23e3c8c903 | |
cora | 7a0c8518a3 | |
cron | 6e8996cd94 | |
cora | 16b41bbd3e | |
cora | e2321f82b7 | |
cora | 1d04bd87d5 | |
cora | bde87dc5a3 | |
cora | a7dcc30ab1 | |
cora | 60b3eeae8b | |
cora | c13deff8de | |
cora | 6af8242717 | |
cora | e3d3ff720e | |
cora | 1a6d018ae6 | |
cora | daee8c89b2 | |
cora | b88f3fd140 | |
cora | 96e1367839 | |
cora | 29ee4e8547 | |
cora | 01aeffa8a7 | |
cora | 227e487bea | |
cora | 82ef888bbb | |
cora | 8e48383812 | |
cora | 58bc30f541 | |
cora | 26b1d072b0 | |
cora | e22714aa6c | |
cron | 01decba5de | |
cron | 8724802b02 | |
cron | 5c52f0b6ba | |
cora | e57f62a186 | |
cora | 2ac62c69b7 | |
cron | af4d3c1e72 | |
cora | 27fc956af9 | |
cora | b9ed498afb | |
cora | a17def93c3 | |
cora | 743516e8cf | |
cron | b6c34f9d5e | |
cora | a0fdbcf45b | |
cora | cd4aa1220a | |
cora | e5ca28f445 | |
cora | 2cda3ac31f | |
cron | d37b416495 | |
cron | d740256b12 | |
cron | ce06e2d824 | |
cora | c76be7b86d | |
cora | 12df80075a | |
cora | cedbb418d0 | |
cora | a4ea9b0400 | |
cora | 3dd9dfb174 | |
cora | 49fc041161 | |
cora | 9408e18089 | |
cora | bf63f35c10 | |
cora | 6439062306 | |
cora | 2ba91e7814 | |
cora | 54cab72945 | |
cora | 428d3c2ba3 | |
cora | a1ea16f10f | |
cora | 093913be33 | |
cora | 37f066bf9c | |
cron | 49515ee77b | |
cron | b3711601ec | |
cron | 394089ee05 | |
cora | 265ee16a2d | |
cron | 48d431ffad | |
cron | 75435d73f9 | |
cron | 434de43a72 | |
cron | db4f5fed9a | |
cron | 78d66a7125 | |
cron | b7dcc4299d | |
cron | e77a5f9e83 | |
cron | 76f3138dbe | |
cron | f1dfe28848 | |
cron | 88c675193a | |
cron | 4be2c31314 | |
cron | b7793dbb9a | |
cron | 3f9f50620d | |
cron | 7b3ebdb460 | |
cron | 627c7d9bcb | |
cron | e30c012771 | |
cron | 33505596ed | |
cron | 6e8c1fb739 | |
cron | 632eb7e286 | |
cron | 16fafaa193 | |
cron | a0434a7225 | |
cron | 0753b8d94d | |
cron | 2ca6d7ef31 | |
cron | 5623c73578 | |
cron | 4c816f1071 | |
cron | 05da1be543 | |
cron | e5f28d8469 | |
cron | 5c3df299a6 | |
cron | 1a8f916fa7 | |
cron | bb55dcad38 | |
cron | d4b2b38133 | |
cron | 5eddb0f02a | |
cron | 7e23013727 | |
cron | 0c0a8236e9 | |
cron | 48da01beb5 | |
cron | 1f0d77b0c4 | |
cron | 8e757040bf | |
cron | ac9f18f6dd | |
cron | 0f8dd9c7f3 | |
cron | 93881793cf | |
cron | a57a8772fa | |
cron | 481f71967b | |
cron | d791294319 | |
cron | 73d9e30816 | |
cron | d6abb183b6 | |
cora | 37efa169d1 | |
cora | f8d8947818 | |
cora | 287de74e55 | |
cora | d2c4108607 | |
cora | 6def65f31d | |
cora | 7a757a8c6a | |
cora | 1f1e7558b0 | |
cora | 4ff2b8bdbb | |
cora | aec3fb38f5 | |
cron | 836e29e653 | |
cron | 7f09824e89 | |
cora | c9b11b7c73 | |
cora | aaffe05463 | |
cron | 2fc69991b0 | |
cora | 472f99d81e | |
cora | a452285e03 | |
cora | aa693c1fbd | |
cora | eaa39a0987 | |
cora | 068252a8dd | |
cora | 0e6e73ad43 | |
cora | 480789b6e6 | |
cora | b1b9f89be3 | |
cora | a28240deb0 | |
cora | 10c6294fa8 | |
cora | 7e082da0f7 | |
cora | 5d9d147444 | |
cora | d58ff5d50e | |
cora | d6f3724f47 | |
cora | 335b710a83 | |
cora | b561de16b5 | |
cron | 1e33e1bb5e | |
cron | b5d311f3e5 | |
cora | bee4d3d326 | |
cora | 510f8da63f | |
cora | 5415d2309b | |
cora | 30db8c2995 | |
cora | 860f40dbd0 | |
cron | 050e2d820e | |
cron | 51c5cfa22d | |
cron | cd81ac60d8 | |
cora | 40b62ac32c | |
cron | ef10d26129 | |
cron | 1abd79b524 | |
cron | 96861cbe4f | |
cora | d201dcca1b | |
cora | 056d3d48de | |
cora | c995b35346 | |
cora | 31fb77cb9f | |
cora | 4803341750 | |
cora | 2c3f917aba | |
cora | 4e5fbf9d33 | |
cora | 176500adbb | |
cron | f99525f9af | |
cora | 24fcdc628e | |
cora | 193c5c2753 | |
cora | c2145684bd | |
cron | e3a0458c3f | |
cron | 2aefaaee92 | |
cron | 7613a0d6f9 | |
cron | 70dcd75369 | |
cron | b1089317d9 | |
cron | 8d8d778fa5 | |
cron | 62e123db2b | |
cron | b386220ffb | |
cron | b7df47c00a | |
cron | 2879ea58a1 | |
cron | 1f53b639a5 | |
cron | 6807c46a27 | |
cron | 3af4dacd60 | |
cron | 7fde73b8ec | |
cron | 7383dc7853 | |
cron | 88d1149d7e | |
cron | e293e1edcc | |
flyc0r | 8d947351e3 | |
cron | abaa0d78d6 | |
cron | 3fa305c42b | |
cron | d499503213 | |
cron | 15d7d69ca1 | |
flyc0r | 007f5f0047 | |
cron | 41bc1562ff | |
cron | 6697a9e235 | |
cron | 4a12c4b818 | |
cron | 2454a8f496 | |
cron | 871c36f2f1 | |
flyc0r | 54ee9d32aa | |
cron | 13f34556d8 | |
flyc0r | eb3149b0b4 | |
flyc0r | dc9799e082 | |
cron | 76b1095268 | |
flyc0r | f486ff7052 | |
flyc0r | 0b130460fe | |
flyc0r | e764cd0114 | |
flyc0r | 2ef1f3e7e9 | |
flyc0r | 437c1e26d9 | |
flyc0r | b138b4f84c | |
flyc0r | 61d7366361 | |
flyc0r | 948c7a6096 | |
flyc0r | 8f6c90e456 | |
cron | 2668e20f48 | |
cron | 1b45fab4c3 | |
cron | aa40a8747a | |
cron | d4b199f3be | |
cron | da884b463b | |
cron | 3efe147d8d | |
cron | 519575a9b3 | |
cron | c5fef6cdc4 | |
flyc0r | 51408076dc | |
flyc0r | 2551ddbf1d | |
cron | 2530004afb | |
cron | a5245322c0 | |
cron | 01eb35645c | |
cron | e7bb8d8cee | |
cron | fde77217cb | |
cron | 69da194461 | |
cron | 887b18936e | |
cron | dd1e75bd82 | |
cron | 9afa61a55d | |
flyc0r | be40b3da54 | |
cron | 750120c494 | |
cron | e5f220693a | |
cron | 57a1f944c9 | |
flyc0r | 5bc3b727af | |
flyc0r | c8d90d5f85 | |
cron | 51e32ac5ba | |
cron | 95c10965d5 | |
cron | 106fab9762 | |
cron | 7652a30c72 | |
cron | 4a1b7bd37a | |
flyc0r | 096ce84ab6 | |
flyc0r | cc4736d025 | |
flyc0r | a269b0d5dc | |
flyc0r | 9363aaa25d | |
cron | 86e96f5dcb | |
flyc0r | 217fd70ee5 | |
flyc0r | 0b832d4f48 | |
flyc0r | 56f8c97fa7 | |
flyc0r | 9e2805235c | |
flyc0r | 7ff2a35474 | |
flyc0r | f24040219a | |
flyc0r | 5c274bbafe | |
flyc0r | 70c925f4ff | |
cron | cf97c5c246 | |
cron | bce8e36fc3 | |
cron | 1ff64b4fa1 | |
cron | 7e3e609825 | |
cron | 7e3c6b9cdd | |
cron | 9ab726e1ed | |
cron | d50e632803 | |
cron | 28371feb4f | |
flyc0r | f3b66c82c5 | |
flyc0r | 0e9e1f3528 |
|
@ -53,7 +53,6 @@ build/.cmake/
|
|||
/worlds
|
||||
/world/
|
||||
/client/mod_storage/
|
||||
/clientmods/*
|
||||
!/clientmods/mods_here.txt
|
||||
|
||||
## Configuration/log files
|
||||
|
|
|
@ -7,7 +7,7 @@ endif()
|
|||
|
||||
# This can be read from ${PROJECT_NAME} after project() is called
|
||||
project(minetest)
|
||||
set(PROJECT_NAME_CAPITALIZED "Dragonfire")
|
||||
set(PROJECT_NAME_CAPITALIZED "waspsaliva")
|
||||
|
||||
# Works only for cmake 3.1 and greater
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
@ -18,7 +18,7 @@ set(CLANG_MINIMUM_VERSION "3.4")
|
|||
set(VERSION_MAJOR 5)
|
||||
set(VERSION_MINOR 4)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||
set(VERSION_EXTRA "-dragonfire" CACHE STRING "Stuff to append to version string") ##set dragonfire to make hackclient detection easier for servers
|
||||
|
||||
# Change to false for releases
|
||||
set(DEVELOPMENT_BUILD FALSE)
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
waspsaliva
|
||||
=========
|
||||
|
||||
This is a hacked client forked from [Dragonfireclient](https://github.com/EliasFleckenstein03/dragonfireclient), itself a fork of Minetest. Build instructions are the same as regular Minetest.
|
||||
|
||||
|
||||
|
||||
Minetest
|
||||
========
|
||||
|
||||
|
|
|
@ -13,11 +13,13 @@ core.cheats = {
|
|||
["AutoJump"] = "autojump",
|
||||
["Jesus"] = "jesus",
|
||||
["NoSlow"] = "no_slow",
|
||||
["AutoForwSprint"] = 'autofsprint',
|
||||
["Jetpack"] = 'jetpack',
|
||||
["SpeedOverride"] = "override_speed",
|
||||
["JumpOverride"] = "override_jump",
|
||||
["GravityOverride"] = "override_gravity",
|
||||
["JetPack"] = "jetpack",
|
||||
["AntiSlip"] = "antislip",
|
||||
["AntiSlip"] = "antislip",
|
||||
["NoPosUpdate"] = "noposupdate",
|
||||
},
|
||||
["Render"] = {
|
||||
["Xray"] = "xray",
|
||||
|
@ -26,6 +28,7 @@ core.cheats = {
|
|||
["NoHurtCam"] = "no_hurt_cam",
|
||||
["BrightNight"] = "no_night",
|
||||
["Coords"] = "coords",
|
||||
["Clouds"] = "enable_clouds",
|
||||
["CheatHUD"] = "cheat_hud",
|
||||
["EntityESP"] = "enable_entity_esp",
|
||||
["EntityTracers"] = "enable_entity_tracers",
|
||||
|
@ -45,6 +48,10 @@ core.cheats = {
|
|||
["EntitySpeed"] = "entity_speed",
|
||||
["ParticleExploit"] = "log_particles",
|
||||
},
|
||||
["Chat"] = {
|
||||
["IgnoreStatus"] = "ignore_status_messages",
|
||||
["Deathmessages"] = "mark_deathmessages",
|
||||
},
|
||||
["Player"] = {
|
||||
["NoFallDamage"] = "prevent_natural_damage",
|
||||
["NoForceRotate"] = "no_force_rotate",
|
||||
|
|
|
@ -10,4 +10,4 @@ dofile(commonpath .. "vector.lua")
|
|||
dofile(clientpath .. "util.lua")
|
||||
dofile(clientpath .. "chatcommands.lua")
|
||||
dofile(clientpath .. "cheats.lua")
|
||||
|
||||
dofile(clientpath .. "wasplib.lua")
|
||||
|
|
|
@ -99,9 +99,14 @@ core.registered_on_dignode, core.register_on_dignode = make_registration()
|
|||
core.registered_on_punchnode, core.register_on_punchnode = make_registration()
|
||||
core.registered_on_placenode, core.register_on_placenode = make_registration()
|
||||
core.registered_on_item_use, core.register_on_item_use = make_registration()
|
||||
core.registered_on_item_activate, core.register_on_item_activate = make_registration()
|
||||
core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
|
||||
core.registered_on_modchannel_signal, core.register_on_modchannel_signal = make_registration()
|
||||
core.registered_on_inventory_open, core.register_on_inventory_open = make_registration()
|
||||
core.registered_on_receiving_inventory_form, core.register_on_receiving_inventory_form = make_registration()
|
||||
core.registered_on_nodemeta_form_open, core.register_on_nodemeta_form_open = make_registration()
|
||||
core.registered_on_recieve_physics_override, core.register_on_recieve_physics_override = make_registration()
|
||||
core.registered_on_play_sound, core.register_on_play_sound = make_registration()
|
||||
core.registered_on_spawn_particle, core.register_on_spawn_particle = make_registration()
|
||||
core.registered_on_sending_inventory_fields, core.register_on_sending_inventory_fields = make_registration()
|
||||
core.registered_on_sending_nodemeta_fields, core.register_on_sending_nodemeta_fields = make_registration()
|
||||
|
|
|
@ -29,16 +29,6 @@ function core.find_item(item, mini, maxi)
|
|||
end
|
||||
end
|
||||
|
||||
function core.switch_to_item(item)
|
||||
local i = core.find_item(item)
|
||||
if i then
|
||||
core.localplayer:set_wield_index(i)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function core.get_pointed_thing()
|
||||
local pos = core.camera:get_pos()
|
||||
local pos2 = vector.add(pos, vector.multiply(core.camera:get_look_dir(), 7))
|
||||
|
|
|
@ -0,0 +1,771 @@
|
|||
|
||||
ws = {}
|
||||
ws.registered_globalhacks = {}
|
||||
ws.displayed_wps={}
|
||||
|
||||
ws.c = core
|
||||
|
||||
local nextact = {}
|
||||
local ghwason={}
|
||||
|
||||
local nodes_this_tick=0
|
||||
|
||||
function ws.s(name,value)
|
||||
if value == nil then
|
||||
return ws.c.settings:get(name)
|
||||
else
|
||||
ws.c.settings:set(name,value)
|
||||
return ws.c.settings:get(name)
|
||||
end
|
||||
end
|
||||
function ws.sb(name,value)
|
||||
if value == nil then
|
||||
return ws.c.settings:get_bool(name)
|
||||
else
|
||||
ws.c.settings:set_bool(name,value)
|
||||
return ws.c.settings:get_bool(name)
|
||||
end
|
||||
end
|
||||
|
||||
function ws.dcm(msg)
|
||||
return minetest.display_chat_message(msg)
|
||||
end
|
||||
function ws.set_bool_bulk(settings,value)
|
||||
if type(settings) ~= 'table' then return false end
|
||||
for k,v in pairs(settings) do
|
||||
minetest.settings:set_bool(v,value)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ws.shuffle(tbl)
|
||||
for i = #tbl, 2, -1 do
|
||||
local j = math.random(i)
|
||||
tbl[i], tbl[j] = tbl[j], tbl[i]
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
function ws.in_list(val, list)
|
||||
if type(list) ~= "table" then return false end
|
||||
for i, v in ipairs(list) do
|
||||
if v == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ws.random_table_element(tbl)
|
||||
local ks = {}
|
||||
for k in pairs(tbl) do
|
||||
table.insert(ks, k)
|
||||
end
|
||||
return tbl[ks[math.random(#ks)]]
|
||||
end
|
||||
|
||||
function ws.center()
|
||||
--local lp=ws.dircoord(0,0,0)
|
||||
--minetest.localplayer:set_pos(lp)
|
||||
end
|
||||
|
||||
function ws.globalhacktemplate(setting,func,funcstart,funcstop,daughters,delay)
|
||||
funcstart = funcstart or function() end
|
||||
funcstop = funcstop or function() end
|
||||
delay = delay or 0.5
|
||||
return function()
|
||||
if not minetest.localplayer then return end
|
||||
if minetest.settings:get_bool(setting) then
|
||||
if tps_client and tps_client.ping and tps_client.ping > 1000 then return end
|
||||
nodes_this_tick = 0
|
||||
if nextact[setting] and nextact[setting] > os.clock() then return end
|
||||
nextact[setting] = os.clock() + delay
|
||||
if not ghwason[setting] then
|
||||
if not funcstart() then
|
||||
ws.set_bool_bulk(daughters,true)
|
||||
ghwason[setting] = true
|
||||
--ws.dcm(setting.. " activated")
|
||||
ws.center()
|
||||
minetest.settings:set('last-dir',ws.getdir())
|
||||
minetest.settings:set('last-y',ws.dircoord(0,0,0).y)
|
||||
else minetest.settings:set_bool(setting,false)
|
||||
end
|
||||
else
|
||||
func()
|
||||
end
|
||||
|
||||
elseif ghwason[setting] then
|
||||
ghwason[setting] = false
|
||||
ws.set_bool_bulk(daughters,false)
|
||||
funcstop()
|
||||
--ws.dcm(setting.. " deactivated")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ws.register_globalhack(func)
|
||||
table.insert(ws.registered_globalhacks,func)
|
||||
end
|
||||
|
||||
function ws.register_globalhacktemplate(name,category,setting,func,funcstart,funcstop,daughters)
|
||||
ws.register_globalhack(ws.globalhacktemplate(setting,func,funcstart,funcstop,daughters))
|
||||
minetest.register_cheat(name,category,setting)
|
||||
end
|
||||
|
||||
ws.rg=ws.register_globalhacktemplate
|
||||
|
||||
function ws.step_globalhacks(dtime)
|
||||
for i, v in ipairs(ws.registered_globalhacks) do
|
||||
v(dtime)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime) ws.step_globalhacks(dtime) end)
|
||||
minetest.settings:set_bool('continuous_forward',false)
|
||||
function ws.on_connect(func)
|
||||
if not minetest.localplayer then minetest.after(0,function() ws.on_connect(func) end) return end
|
||||
if func then func() end
|
||||
end
|
||||
|
||||
ws.on_connect(function()
|
||||
local ldir =minetest.settings:get('last-dir')
|
||||
if ldir then ws.setdir(ldir) end
|
||||
end)
|
||||
|
||||
|
||||
-- COORD MAGIC
|
||||
|
||||
function ws.is_same_pos(pos1,pos2)
|
||||
return vector.distance(vector.round(pos1),vector.round(pos2)) == 0
|
||||
end
|
||||
function ws.get_reachable_positions(range,under)
|
||||
under=under or false
|
||||
range=range or 2
|
||||
local rt={}
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local ylim=range
|
||||
if under then ylim=-1 end
|
||||
for x = -range,range,1 do
|
||||
for y = -range,ylim,1 do
|
||||
for z = -range,range,1 do
|
||||
table.insert(rt,vector.add(lp,vector.new(x,y,z)))
|
||||
end
|
||||
end
|
||||
end
|
||||
return rt
|
||||
end
|
||||
|
||||
function ws.do_area(radius,func,plane)
|
||||
for k,v in pairs(ws.get_reachable_positions(range)) do
|
||||
if not plane or v.y == minetest.localplayer:get_pos().y -1 then
|
||||
func(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ws.display_wp(pos,name)
|
||||
local ix = #ws.displayed_wps + 1
|
||||
ws.displayed_wps[ix] = minetest.localplayer:hud_add({
|
||||
hud_elem_type = 'waypoint',
|
||||
name = name,
|
||||
text = name,
|
||||
number = 0x00ff00,
|
||||
world_pos = pos
|
||||
})
|
||||
return ix
|
||||
end
|
||||
|
||||
function ws.clear_wp(ix)
|
||||
table.remove(ws.displayed_wps,ix)
|
||||
end
|
||||
|
||||
function ws.clear_wps()
|
||||
for k,v in ipairs(ws.displayed_wps) do
|
||||
minetest.localplayer:hud_remove(v)
|
||||
table.remove(ws.displayed_wps,k)
|
||||
end
|
||||
end
|
||||
|
||||
function ws.register_chatcommand_alias(old, ...)
|
||||
local def = assert(minetest.registered_chatcommands[old])
|
||||
def.name = nil
|
||||
for i = 1, select('#', ...) do
|
||||
minetest.register_chatcommand(select(i, ...), table.copy(def))
|
||||
end
|
||||
end
|
||||
|
||||
function ws.round2(num, numDecimalPlaces)
|
||||
return tonumber(string.format("%." .. (numDecimalPlaces or 0) .. "f", num))
|
||||
end
|
||||
|
||||
function ws.pos_to_string(pos)
|
||||
if type(pos) == 'table' then
|
||||
pos = minetest.pos_to_string(vector.round(pos))
|
||||
end
|
||||
if type(pos) == 'string' then
|
||||
return pos
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
function ws.string_to_pos(pos)
|
||||
if type(pos) == 'string' then
|
||||
pos = minetest.string_to_pos(pos)
|
||||
end
|
||||
if type(pos) == 'table' then
|
||||
return vector.round(pos)
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
|
||||
|
||||
--ITEMS
|
||||
function ws.find_item_in_table(items,rnd)
|
||||
if type(items) == 'string' then
|
||||
return minetest.find_item(items)
|
||||
end
|
||||
if type(items) ~= 'table' then return end
|
||||
if rnd then items=ws.shuffle(items) end
|
||||
for i, v in pairs(items) do
|
||||
local n = minetest.find_item(v)
|
||||
if n then
|
||||
return n
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ws.find_named(inv, name)
|
||||
if not inv then return -1 end
|
||||
if not name then return end
|
||||
for i, v in ipairs(inv) do
|
||||
if v:get_name():find(name) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
local hotbar_slot=8
|
||||
function ws.to_hotbar(it,hslot)
|
||||
local tpos=nil
|
||||
local plinv = minetest.get_inventory("current_player")
|
||||
if hslot and hslot < 10 then
|
||||
tpos=hslot
|
||||
else
|
||||
for i, v in ipairs(plinv.main) do
|
||||
if i<10 and v:is_empty() then
|
||||
tpos = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if tpos == nil then tpos=hotbar_slot end
|
||||
local mv = InventoryAction("move")
|
||||
mv:from("current_player", "main", it)
|
||||
mv:to("current_player", "main", tpos)
|
||||
mv:apply()
|
||||
return tpos
|
||||
end
|
||||
|
||||
function ws.switch_to_item(itname,hslot)
|
||||
if not minetest.localplayer then return false end
|
||||
local plinv = minetest.get_inventory("current_player")
|
||||
for i, v in ipairs(plinv.main) do
|
||||
if i<10 and v:get_name() == itname then
|
||||
minetest.localplayer:set_wield_index(i)
|
||||
return true
|
||||
end
|
||||
end
|
||||
local pos = ws.find_named(plinv.main, itname)
|
||||
if pos then
|
||||
minetest.localplayer:set_wield_index(ws.to_hotbar(pos,hslot))
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function core.switch_to_item(item) return ws.switch_to_item(item) end
|
||||
|
||||
function ws.switch_inv_or_echest(name,max_count,hslot)
|
||||
if not minetest.localplayer then return false end
|
||||
local plinv = minetest.get_inventory("current_player")
|
||||
if ws.switch_to_item(name) then return true end
|
||||
|
||||
local epos = ws.find_named(plinv.enderchest, name)
|
||||
if epos then
|
||||
local tpos
|
||||
for i, v in ipairs(plinv.main) do
|
||||
if i < 9 and v:is_empty() then
|
||||
tpos = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if not tpos then tpos=hotbar_slot end
|
||||
|
||||
if tpos then
|
||||
local mv = InventoryAction("move")
|
||||
mv:from("current_player", "enderchest", epos)
|
||||
mv:to("current_player", "main", tpos)
|
||||
if max_count then
|
||||
mv:set_count(max_count)
|
||||
end
|
||||
mv:apply()
|
||||
minetest.localplayer:set_wield_index(tpos)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function posround(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
local function fmt(c)
|
||||
return tostring(posround(c.x))..","..tostring(posround(c.y))..","..tostring(posround(c.z))
|
||||
end
|
||||
|
||||
local function map_pos(value)
|
||||
if value.x then
|
||||
return value
|
||||
else
|
||||
return {x = value[1], y = value[2], z = value[3]}
|
||||
end
|
||||
end
|
||||
|
||||
function ws.invparse(location)
|
||||
if type(location) == "string" then
|
||||
if string.match(location, "^[-]?[0-9]+,[-]?[0-9]+,[-]?[0-9]+$") then
|
||||
return "nodemeta:" .. location
|
||||
else
|
||||
return location
|
||||
end
|
||||
elseif type(location) == "table" then
|
||||
return "nodemeta:" .. fmt(map_pos(location))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- TOOLS
|
||||
|
||||
|
||||
local function check_tool(stack, node_groups, old_best_time)
|
||||
local toolcaps = stack:get_tool_capabilities()
|
||||
if not toolcaps then return end
|
||||
local best_time = old_best_time
|
||||
for group, groupdef in pairs(toolcaps.groupcaps) do
|
||||
local level = node_groups[group]
|
||||
if level then
|
||||
local this_time = groupdef.times[level]
|
||||
if this_time and this_time < best_time then
|
||||
best_time = this_time
|
||||
end
|
||||
end
|
||||
end
|
||||
return best_time < old_best_time, best_time
|
||||
end
|
||||
|
||||
local function find_best_tool(nodename, switch)
|
||||
local player = minetest.localplayer
|
||||
local inventory = minetest.get_inventory("current_player")
|
||||
local node_groups = minetest.get_node_def(nodename).groups
|
||||
local new_index = player:get_wield_index()
|
||||
local is_better, best_time = false, math.huge
|
||||
|
||||
is_better, best_time = check_tool(player:get_wielded_item(), node_groups, best_time)
|
||||
if inventory.hand then
|
||||
is_better, best_time = check_tool(inventory.hand[1], node_groups, best_time)
|
||||
end
|
||||
|
||||
for index, stack in ipairs(inventory.main) do
|
||||
is_better, best_time = check_tool(stack, node_groups, best_time)
|
||||
if is_better then
|
||||
new_index = index
|
||||
end
|
||||
end
|
||||
|
||||
return new_index,best_time
|
||||
end
|
||||
|
||||
function ws.get_digtime(nodename)
|
||||
local idx,tm=find_best_tool(nodename)
|
||||
return tm
|
||||
end
|
||||
|
||||
function ws.select_best_tool(pos)
|
||||
local nd=minetest.get_node_or_nil(pos)
|
||||
local nodename='air'
|
||||
if nd then nodename=nd.name end
|
||||
local t=find_best_tool(nodename)
|
||||
minetest.localplayer:set_wield_index(ws.to_hotbar(t,hotbar_slot))
|
||||
--minetest.localplayer:set_wield_index(find_best_tool(nodename))
|
||||
end
|
||||
|
||||
--- COORDS
|
||||
function ws.coord(x, y, z)
|
||||
return vector.new(x,y,z)
|
||||
end
|
||||
function ws.ordercoord(c)
|
||||
if c.x == nil then
|
||||
return {x = c[1], y = c[2], z = c[3]}
|
||||
else
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
-- x or {x,y,z} or {x=x,y=y,z=z}
|
||||
function ws.optcoord(x, y, z)
|
||||
if y and z then
|
||||
return ws.coord(x, y, z)
|
||||
else
|
||||
return ws.ordercoord(x)
|
||||
end
|
||||
end
|
||||
function ws.cadd(c1, c2)
|
||||
return vector.add(c1,c2)
|
||||
--return ws.coord(c1.x + c2.x, c1.y + c2.y, c1.z + c2.z)
|
||||
end
|
||||
|
||||
function ws.relcoord(x, y, z, rpos)
|
||||
local pos = rpos or minetest.localplayer:get_pos()
|
||||
pos.y=math.ceil(pos.y)
|
||||
--math.floor(pos.y) + 0.5
|
||||
return ws.cadd(pos, ws.optcoord(x, y, z))
|
||||
end
|
||||
|
||||
local function between(x, y, z) -- x is between y and z (inclusive)
|
||||
return y <= x and x <= z
|
||||
end
|
||||
|
||||
function ws.getdir(yaw) --
|
||||
local rot = yaw or minetest.localplayer:get_yaw() % 360
|
||||
if between(rot, 315, 360) or between(rot, 0, 45) then
|
||||
return "north"
|
||||
elseif between(rot, 135, 225) then
|
||||
return "south"
|
||||
elseif between(rot, 225, 315) then
|
||||
return "east"
|
||||
elseif between(rot, 45, 135) then
|
||||
return "west"
|
||||
end
|
||||
end
|
||||
|
||||
function ws.getaxis()
|
||||
local dir=ws.getdir()
|
||||
if dir == "north" or dir == "south" then return "z" end
|
||||
return "x"
|
||||
end
|
||||
function ws.setdir(dir) --
|
||||
if dir == "north" then
|
||||
minetest.localplayer:set_yaw(0)
|
||||
elseif dir == "south" then
|
||||
minetest.localplayer:set_yaw(180)
|
||||
elseif dir == "east" then
|
||||
minetest.localplayer:set_yaw(270)
|
||||
elseif dir == "west" then
|
||||
minetest.localplayer:set_yaw(90)
|
||||
end
|
||||
end
|
||||
|
||||
function ws.dircoord(f, y, r ,rpos, rdir)
|
||||
local dir= ws.getdir(rdir)
|
||||
local coord = ws.optcoord(f, y, r)
|
||||
local f = coord.x
|
||||
local y = coord.y
|
||||
local r = coord.z
|
||||
local lp= rpos or minetest.localplayer:get_pos()
|
||||
if dir == "north" then
|
||||
return ws.relcoord(r, y, f,rpos)
|
||||
elseif dir == "south" then
|
||||
return ws.relcoord(-r, y, -f,rpos)
|
||||
elseif dir == "east" then
|
||||
return ws.relcoord(f, y, -r,rpos)
|
||||
elseif dir== "west" then
|
||||
return ws.relcoord(-f, y, r,rpos)
|
||||
end
|
||||
return ws.relcoord(0, 0, 0,rpos)
|
||||
end
|
||||
|
||||
function ws.get_dimension(pos)
|
||||
if pos.y > -65 then return "overworld"
|
||||
elseif pos.y > -8000 then return "void"
|
||||
elseif pos.y > -27000 then return "end"
|
||||
elseif pos.y > -28930 then return "void"
|
||||
elseif pos.y > -31000 then return "nether"
|
||||
else return "void"
|
||||
end
|
||||
end
|
||||
|
||||
function ws.aim(tpos)
|
||||
local ppos=minetest.localplayer:get_pos()
|
||||
local dir=vector.direction(ppos,tpos)
|
||||
local yyaw=0;
|
||||
local pitch=0;
|
||||
if dir.x < 0 then
|
||||
yyaw = math.atan2(-dir.x, dir.z) + (math.pi * 2)
|
||||
else
|
||||
yyaw = math.atan2(-dir.x, dir.z)
|
||||
end
|
||||
yyaw = ws.round2(math.deg(yyaw),2)
|
||||
pitch = ws.round2(math.deg(math.asin(-dir.y) * 1),2);
|
||||
minetest.localplayer:set_yaw(yyaw)
|
||||
minetest.localplayer:set_pitch(pitch)
|
||||
end
|
||||
|
||||
function ws.gaim(tpos,v,g)
|
||||
local v = v or 40
|
||||
local g = g or 9.81
|
||||
local ppos=minetest.localplayer:get_pos()
|
||||
local dir=vector.direction(ppos,tpos)
|
||||
local yyaw=0;
|
||||
local pitch=0;
|
||||
if dir.x < 0 then
|
||||
yyaw = math.atan2(-dir.x, dir.z) + (math.pi * 2)
|
||||
else
|
||||
yyaw = math.atan2(-dir.x, dir.z)
|
||||
end
|
||||
yyaw = ws.round2(math.deg(yyaw),2)
|
||||
local y = dir.y
|
||||
dir.y = 0
|
||||
local x = vector.length(dir)
|
||||
pitch=math.atan(math.pow(v, 2) / (g * x) + math.sqrt(math.pow(v, 4)/(math.pow(g, 2) * math.pow(x, 2)) - 2 * math.pow(v, 2) * y/(g * math.pow(x, 2)) - 1))
|
||||
--pitch = ws.round2(math.deg(math.asin(-dir.y) * 1),2);
|
||||
minetest.localplayer:set_yaw(yyaw)
|
||||
minetest.localplayer:set_pitch(math.deg(pitch))
|
||||
end
|
||||
|
||||
local function tablearg(arg)
|
||||
local tb={}
|
||||
if type(arg) == 'string' then
|
||||
tb={arg}
|
||||
elseif type(arg) == 'table' then
|
||||
tb=arg
|
||||
elseif type(arg) == 'function' then
|
||||
tb=arg()
|
||||
end
|
||||
return tb
|
||||
end
|
||||
|
||||
function ws.isnode(pos,arg)--arg is either an itemstring, a table of itemstrings or a function returning an itemstring
|
||||
local nodename=tablearg(arg)
|
||||
local nd=minetest.get_node_or_nil(pos)
|
||||
if nd and nodename and ws.in_list(nd.name,nodename) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function ws.can_place_at(pos)
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
return (node and (node.name == "air" or node.name=="mcl_core:water_source" or node.name=="mcl_core:water_flowing" or node.name=="mcl_core:lava_source" or node.name=="mcl_core:lava_flowing" or minetest.get_node_def(node.name).buildable_to))
|
||||
end
|
||||
|
||||
-- should check if wield is placeable
|
||||
-- minetest.get_node(wielded:get_name()) ~= nil should probably work
|
||||
-- otherwise it equips armor and eats food
|
||||
function ws.can_place_wielded_at(pos)
|
||||
local wield_empty = minetest.localplayer:get_wielded_item():is_empty()
|
||||
return not wield_empty and ws.can_place_at(pos)
|
||||
end
|
||||
|
||||
|
||||
function ws.find_any_swap(items,hslot)
|
||||
hslot=hslot or 8
|
||||
for i, v in ipairs(items) do
|
||||
local n = minetest.find_item(v)
|
||||
if n then
|
||||
ws.switch_to_item(v,hslot)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- swaps to any of the items and places if need be
|
||||
-- returns true if placed and in inventory or already there, false otherwise
|
||||
|
||||
local lastact=0
|
||||
local lastplc=0
|
||||
local lastdig=0
|
||||
local actint=10
|
||||
function ws.place(pos,items,hslot, place)
|
||||
--if nodes_this_tick > 8 then return end
|
||||
--nodes_this_tick = nodes_this_tick + 1
|
||||
--if not inside_constraints(pos) then return end
|
||||
if not pos then return end
|
||||
items=tablearg(items)
|
||||
|
||||
place = place or minetest.place_node
|
||||
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if not node then return end
|
||||
-- already there
|
||||
if ws.isnode(pos,items) then
|
||||
return true
|
||||
else
|
||||
local swapped = ws.find_any_swap(items,hslot)
|
||||
|
||||
-- need to place
|
||||
if swapped and ws.can_place_at(pos) then
|
||||
--minetest.after("0.05",place,pos)
|
||||
place(pos)
|
||||
return true
|
||||
-- can't place
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ws.place_if_able(pos)
|
||||
if not pos then return end
|
||||
if not inside_constraints(pos) then return end
|
||||
if ws.can_place_wielded_at(pos) then
|
||||
minetest.place_node(pos)
|
||||
end
|
||||
end
|
||||
|
||||
function ws.is_diggable(pos)
|
||||
if not pos then return false end
|
||||
local nd=minetest.get_node_or_nil(pos)
|
||||
if not nd then return false end
|
||||
local n = minetest.get_node_def(nd.name)
|
||||
if n and n.diggable then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function ws.dig(pos,condition,autotool)
|
||||
--if not inside_constraints(pos) then return end
|
||||
if autotool == nil then autotool = true end
|
||||
if condition and not condition(pos) then return false end
|
||||
if not ws.is_diggable(pos) then return end
|
||||
local nd=minetest.get_node_or_nil(pos)
|
||||
if nd and minetest.get_node_def(nd.name).diggable then
|
||||
if autotool then ws.select_best_tool(pos) end
|
||||
minetest.dig_node(pos)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ws.chunk_loaded()
|
||||
local ign=minetest.find_nodes_near(ws.dircoord(0,0,0),10,{'ignore'},true)
|
||||
if #ign == 0 then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function ws.get_near(nodes,range)
|
||||
range=range or 5
|
||||
local nds=minetest.find_nodes_near(ws.dircoord(0,0,0),rang,nodes,true)
|
||||
if #nds > 0 then return nds end
|
||||
return false
|
||||
end
|
||||
|
||||
function ws.is_laggy()
|
||||
if tps_client and tps_client.ping and tps_client.ping > 1000 then return true end
|
||||
end
|
||||
|
||||
|
||||
function ws.donodes(poss,func,condition)
|
||||
if ws.is_laggy() then return end
|
||||
local dn_i=0
|
||||
for k,v in pairs(poss) do
|
||||
local nd=minetest.get_node_or_nil(v)
|
||||
if nd and nd.name ~= 'air' then
|
||||
if k > 8 then
|
||||
return
|
||||
end
|
||||
if condition == nil or condition(v) then
|
||||
func(v)
|
||||
dn_i = dn_i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ws.dignodes(poss,condition)
|
||||
local func=function(p) ws.dig(p) end
|
||||
ws.donodes(poss,func,condition)
|
||||
end
|
||||
|
||||
|
||||
function ws.replace(pos,arg)
|
||||
arg=tablearg(arg)
|
||||
local nd=minetest.get_node_or_nil(pos)
|
||||
if nd and not ws.in_list(nd.name,arg) and nd.name ~= 'air' then
|
||||
local tm=ws.get_digtime(nd.name) or 0
|
||||
ws.dig(pos)
|
||||
minetest.after(tm + 0.1,function()
|
||||
ws.place(pos,arg)
|
||||
end)
|
||||
else
|
||||
ws.place(pos,arg)
|
||||
end
|
||||
end
|
||||
|
||||
function ws.playeron(p)
|
||||
local pls=minetest.get_player_names()
|
||||
for k,v in pairs(pls) do
|
||||
if v == p then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function ws.between(x, y, z) -- x is between y and z (inclusive)
|
||||
return y <= x and x <= z
|
||||
end
|
||||
|
||||
|
||||
local wall_pos1={x=-1255,y=6,z=792}
|
||||
local wall_pos2={x=-1452,y=80,z=981}
|
||||
local iwall_pos1={x=-1266,y=6,z=802}
|
||||
local iwall_pos2={x=-1442,y=80,z=971}
|
||||
|
||||
function ws.in_cube(tpos,wpos1,wpos2)
|
||||
local xmax=wpos2.x
|
||||
local xmin=wpos1.x
|
||||
|
||||
local ymax=wpos2.y
|
||||
local ymin=wpos1.y
|
||||
|
||||
local zmax=wpos2.z
|
||||
local zmin=wpos1.z
|
||||
if wpos1.x > wpos2.x then
|
||||
xmax=wpos1.x
|
||||
xmin=wpos2.x
|
||||
end
|
||||
if wpos1.y > wpos2.y then
|
||||
ymax=wpos1.y
|
||||
ymin=wpos2.y
|
||||
end
|
||||
if wpos1.z > wpos2.z then
|
||||
zmax=wpos1.z
|
||||
zmin=wpos2.z
|
||||
end
|
||||
if ws.between(tpos.x,xmin,xmax) and ws.between(tpos.y,ymin,ymax) and ws.between(tpos.z,zmin,zmax) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ws.in_wall(pos)
|
||||
if ws.in_cube(pos,wall_pos1,wall_pos2) and not in_cube(pos,iwall_pos1,iwall_pos2) then
|
||||
return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function ws.inside_wall(pos)
|
||||
local p1=iwall_pos1
|
||||
local p2=iwall_pos2
|
||||
if ws.in_cube(pos,p1,p2) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- DEBUG
|
||||
local function printwieldedmeta()
|
||||
ws.dcm(dump(minetest.localplayer:get_wielded_item():get_meta():to_table()))
|
||||
end
|
||||
minetest.register_cheat('ItemMeta','Test',printwieldedmeta)
|
|
@ -148,6 +148,49 @@ if INIT == "client" then
|
|||
return do_help_cmd(nil, param)
|
||||
end,
|
||||
})
|
||||
|
||||
function core.register_list_command(command, desc, setting)
|
||||
local def = {}
|
||||
def.description = desc
|
||||
def.params = "del <item> | add <item> | list"
|
||||
function def.func(param)
|
||||
local list = (minetest.settings:get(setting) or ""):split(",")
|
||||
if param == "list" then
|
||||
return true, table.concat(list, ", ")
|
||||
else
|
||||
local sparam = param:split(" ")
|
||||
local cmd = sparam[1]
|
||||
local item = sparam[2]
|
||||
if cmd == "del" then
|
||||
if not item then
|
||||
return false, "Missing item."
|
||||
end
|
||||
local i = table.indexof(list, item)
|
||||
if i == -1 then
|
||||
return false, item .. " is not on the list."
|
||||
else
|
||||
table.remove(list, i)
|
||||
core.settings:set(setting, table.concat(list, ","))
|
||||
return true, "Removed " .. item .. " from the list."
|
||||
end
|
||||
elseif cmd == "add" then
|
||||
if not item then
|
||||
return false, "Missing item."
|
||||
end
|
||||
local i = table.indexof(list, item)
|
||||
if i ~= -1 then
|
||||
return false, item .. " is already on the list."
|
||||
else
|
||||
table.insert(list, item)
|
||||
core.settings:set(setting, table.concat(list, ","))
|
||||
return true, "Added " .. item .. " to the list."
|
||||
end
|
||||
end
|
||||
end
|
||||
return false, "Invalid usage. (See /help " .. command .. ")"
|
||||
end
|
||||
core.register_chatcommand(command, def)
|
||||
end
|
||||
else
|
||||
core.register_chatcommand("help", {
|
||||
params = "[all | privs | <cmd>]",
|
||||
|
|
|
@ -47,22 +47,28 @@ end
|
|||
function mm_texture.reset()
|
||||
mm_texture.gameid = nil
|
||||
local have_bg = false
|
||||
local have_overlay = mm_texture.set_generic("overlay")
|
||||
--local have_overlay = mm_texture.set_generic("overlay")
|
||||
|
||||
core.set_clouds(false)
|
||||
mm_texture.clear("header")
|
||||
mm_texture.clear("footer")
|
||||
core.set_clouds(false)
|
||||
mm_texture.set_generic("footer")
|
||||
mm_texture.set_generic("header")
|
||||
local minimalpath = defaulttexturedir .. "menu_bg.png"
|
||||
core.set_background("background", minimalpath, false, 128)
|
||||
if true then return end
|
||||
if not have_overlay then
|
||||
have_bg = mm_texture.set_generic("background")
|
||||
end
|
||||
|
||||
mm_texture.clear("header")
|
||||
mm_texture.clear("footer")
|
||||
core.set_clouds(false)
|
||||
|
||||
mm_texture.set_generic("footer")
|
||||
mm_texture.set_generic("header")
|
||||
|
||||
|
||||
|
||||
if not have_bg then
|
||||
if core.settings:get_bool("menu_clouds") then
|
||||
core.set_clouds(true)
|
||||
core.set_clouds(false)
|
||||
else
|
||||
mm_texture.set_dirt_bg()
|
||||
end
|
||||
|
@ -172,12 +178,12 @@ function mm_texture.set_game(identifier, gamedetails)
|
|||
end
|
||||
|
||||
function mm_texture.set_dirt_bg()
|
||||
if mm_texture.texturepack ~= nil then
|
||||
local path = mm_texture.texturepack .. DIR_DELIM .."default_dirt.png"
|
||||
if core.set_background("background", path, true, 128) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
--if mm_texture.texturepack ~= nil then
|
||||
--local path = mm_texture.texturepack .. DIR_DELIM .."default_dirt.png"
|
||||
--if core.set_background("background", path, true, 128) then
|
||||
-- return true
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- Use universal fallback texture in textures/base/pack
|
||||
local minimalpath = defaulttexturedir .. "menu_bg.png"
|
||||
|
|
|
@ -1201,6 +1201,9 @@ movement_acceleration_air (Acceleration in air) float 2
|
|||
# in nodes per second per second.
|
||||
movement_acceleration_fast (Fast mode acceleration) float 10
|
||||
|
||||
# Ignore server sent walk speed
|
||||
movement_ignore_server_speed (Ignore Server Sent Speed) bool false
|
||||
|
||||
# Walking and flying speed, in nodes per second.
|
||||
movement_speed_walk (Walking speed) float 4
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
pwf=$HOME/.mtpw
|
||||
if [ -z $1 ]; then echo "usage: clammt altname - (common) password must be in $pwf"; exit 1; fi
|
||||
mt=$(dirname $0)/automt
|
||||
pw=$(cat $pwf)
|
||||
$mt clam-ity.minecity.online $1 $pw
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
local function look_nearest()
|
||||
if not minetest.localplayer then return end
|
||||
for k, v in ipairs(minetest.localplayer.get_nearby_objects(10)) do
|
||||
if (v:is_player() and v:get_name() ~= minetest.localplayer:get_name()) then
|
||||
local pos = v:get_pos()
|
||||
pos.y = pos.y - 1
|
||||
autofly.aim(pos)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if minetest.settings:get_bool("autoaim") then
|
||||
look_nearest()
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_cheat("Autoaim", "Combat", "autoaim")
|
|
@ -0,0 +1,264 @@
|
|||
|
||||
-- TODO
|
||||
--[[
|
||||
free space could be a concern
|
||||
traverse_recurse should replace groups with the concrete item
|
||||
maybe recursions yield an item name?
|
||||
that way has_sub could indicate the item which would be yielded in traverse_recurse and replaced in the recipe before being queued
|
||||
autocraft.recipes should be loaded and custom per modset
|
||||
it might choke on empty items in the recipe
|
||||
this needs to handle groups a bit better, i dont think it will mix woods/etc
|
||||
--]]
|
||||
|
||||
autocraft = {}
|
||||
|
||||
|
||||
autocraft.recipes = {
|
||||
["mcl_core:crafting_table"] = {
|
||||
recipes = {
|
||||
{
|
||||
recipe = {
|
||||
{"group:planks", "group:planks"},
|
||||
{"group:planks", "group:planks"}}
|
||||
}
|
||||
}
|
||||
},
|
||||
["mcl_core:wood"] = {
|
||||
groups = {"planks"},
|
||||
recipes = {
|
||||
{
|
||||
count = 4,
|
||||
recipe = {
|
||||
"mcl_core:tree"
|
||||
},
|
||||
shapeless = true -- redundant, can detect from the lack of subtables
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autocraft.groups = {}
|
||||
|
||||
-- extract groups from autocraft.recipes
|
||||
local function group_arrange()
|
||||
for k, v in pairs(autocraft.recipes) do
|
||||
if v.groups then
|
||||
for gi, gv in ipairs(v.groups) do
|
||||
if not autocraft.groups[gv] then
|
||||
autocraft.groups[gv] = {}
|
||||
end
|
||||
|
||||
table.insert(autocraft.groups[gv], k)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
group_arrange()
|
||||
|
||||
local function startswith(str, start)
|
||||
return string.sub(str, 1, #start) == start
|
||||
end
|
||||
|
||||
local function combine(t1, t2)
|
||||
local t1l = #t1
|
||||
local o = {}
|
||||
|
||||
for i, v in ipairs(t1) do
|
||||
o[i] = v
|
||||
end
|
||||
|
||||
for i, v in ipairs(t2) do
|
||||
o[t1l + i] = v
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
local function parse_group(str)
|
||||
if startswith(str, "group:") then
|
||||
return str:match("group:(.+)")
|
||||
end
|
||||
end
|
||||
|
||||
-- get recipes for an item/group
|
||||
local function get_recipes(str)
|
||||
local group = parse_group(str)
|
||||
|
||||
if group then
|
||||
local o = {}
|
||||
|
||||
if autocraft.groups[group] then
|
||||
for i, v in ipairs(autocraft.groups[group]) do
|
||||
o = combine(o, get_recipes(v))
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
else
|
||||
local idef = autocraft.recipes[str]
|
||||
if idef then
|
||||
local o = idef.recipes
|
||||
|
||||
for i, v in ipairs(o) do
|
||||
v.name = str
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
end
|
||||
|
||||
return {}
|
||||
end
|
||||
|
||||
-- count up all the items in the player's inventory
|
||||
-- output:
|
||||
-- {
|
||||
-- item = n,
|
||||
-- item = n
|
||||
-- }
|
||||
local function count_inv()
|
||||
local o = {}
|
||||
local lpim = minetest.get_inventory("current_player").main
|
||||
|
||||
for i, v in ipairs(lpim) do
|
||||
if not v:is_empty() then
|
||||
o[v:get_name()] = (o[v:get_name()] or 0) + v:get_count()
|
||||
end
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
-- effectively turn a recipe shapeless
|
||||
local function flatten_recipe(recipe)
|
||||
if type(recipe[1]) == "table" then
|
||||
local o = {}
|
||||
|
||||
for i, v in ipairs(recipe) do
|
||||
o = combine(o, v)
|
||||
end
|
||||
|
||||
return o
|
||||
else
|
||||
return recipe
|
||||
end
|
||||
end
|
||||
|
||||
-- count the requirements for a recipe, uses count_inv format
|
||||
local function count_recipe(recipe)
|
||||
local o = {}
|
||||
|
||||
for i, v in ipairs(flatten_recipe(recipe)) do
|
||||
local item = ItemStack(v)
|
||||
o[item:get_name()] = (o[item:get_name()] or 0) + item:get_count()
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
-- get all item strings for an item or group string
|
||||
local function get_items_of(str)
|
||||
local group = parse_group(str)
|
||||
|
||||
if group then
|
||||
return autocraft.groups[group]
|
||||
else
|
||||
return {str}
|
||||
end
|
||||
end
|
||||
|
||||
-- check if the recipe can be crafted with current resources
|
||||
local function can_craft(resources, recipe)
|
||||
for k, count in pairs(count_recipe(recipe)) do
|
||||
for i, vv in ipairs(get_items_of(k)) do
|
||||
local item = ItemStack(vv)
|
||||
if (resources[item:get_name()] or 0) >= count then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- traverse all items in a recipe
|
||||
local function recurse_recipe(resources, queue, recipe)
|
||||
for i, v in ipairs(flatten_recipe(recipe)) do
|
||||
if not autocraft.traverse_recurse(resources, queue, ItemStack(v)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- checks if the item/group is in the resource list and subtracts it
|
||||
-- is the base case for traverse_recurse
|
||||
local function has_sub(resources, item)
|
||||
for i, v in ipairs(get_items_of(item:get_name())) do
|
||||
if resources[v] and resources[v] >= item:get_count() then
|
||||
resources[v] = resources[v] - item:get_count()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- enqueues a recipe for an item and its needed sub items
|
||||
function autocraft.traverse_recurse(resources, queue, item)
|
||||
if type(item) == "string" then
|
||||
item = ItemStack(item)
|
||||
end
|
||||
|
||||
-- base case, uncraftibles/already in inventory
|
||||
if has_sub(resources, item) then
|
||||
return true
|
||||
else
|
||||
for i, v in ipairs(get_recipes(item:get_name())) do
|
||||
if can_craft(resources, v.recipe) then
|
||||
if recurse_recipe(resources, queue, v.recipe) then
|
||||
table.insert(queue, v.recipe)
|
||||
|
||||
local tgt = item:get_count()
|
||||
local result = v.count or 1
|
||||
local delta = tgt - result
|
||||
|
||||
resources[v.name] = (resources[v.name] or 0) + result
|
||||
|
||||
if delta > 0 then
|
||||
item:set_count(delta)
|
||||
traverse_recurse(resources, queue, item)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- not enough resources
|
||||
return false
|
||||
end
|
||||
|
||||
-- create a crafting queue for an item
|
||||
-- return queue if enough resources, nil if not
|
||||
function autocraft.traverse(item)
|
||||
local queue = {}
|
||||
local resources = count_inv()
|
||||
|
||||
if autocraft.traverse_recurse(resources, queue, item) then
|
||||
return queue
|
||||
end
|
||||
end
|
||||
|
||||
-- craft a traversed craft tree
|
||||
local function queuecraft(tree)
|
||||
|
||||
end
|
||||
|
||||
-- make a queue and craft it
|
||||
function autocraft.craft(item)
|
||||
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = autocraft
|
||||
author = emilia
|
||||
description = Automatic crafting. Supports crafting blocks (Mineclone) and custom crafting trees.
|
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
@ -0,0 +1,2 @@
|
|||
# autoeat
|
||||
A dragonfire CSM to automatically eat when a certain hunger is reached (MineClone2).
|
|
@ -0,0 +1,76 @@
|
|||
autoeat = {}
|
||||
autoeat.lock = false
|
||||
|
||||
local autodupe = false --rawget(_G, "autodupe")
|
||||
local hud_id = nil
|
||||
|
||||
local function get_float(name, default)
|
||||
return tonumber(minetest.settings:get("autoeat_" .. name) or "") or default
|
||||
end
|
||||
|
||||
local etime = 0
|
||||
|
||||
function autoeat.eat()
|
||||
local food_index
|
||||
local food_count = 0
|
||||
for index, stack in pairs(minetest.get_inventory("current_player").main) do
|
||||
local stackname = stack:get_name()
|
||||
if stackname ~= "" then
|
||||
local def = minetest.get_item_def(stackname)
|
||||
if def and def.groups.food then
|
||||
food_count = food_count + 1
|
||||
if food_index then
|
||||
break
|
||||
end
|
||||
food_index = index
|
||||
end
|
||||
end
|
||||
end
|
||||
if food_index then
|
||||
if food_count == 1 and autodupe then
|
||||
--autodupe.needed(food_index)
|
||||
autoeat.lock = true
|
||||
else
|
||||
local player = minetest.localplayer
|
||||
local old_index = player:get_wield_index()
|
||||
player:set_wield_index(food_index)
|
||||
--minetest.interact("activate", {type = "nothing"})
|
||||
minetest.place_node(minetest.localplayer:get_pos())
|
||||
player:set_wield_index(old_index)
|
||||
autoeat.lock = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function autoeat.get_hunger()
|
||||
if hud_id then
|
||||
return minetest.localplayer:hud_get(hud_id).number
|
||||
else
|
||||
return 20
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if not minetest.localplayer then return end
|
||||
etime = etime + dtime
|
||||
if autoeat.lock or minetest.settings:get_bool("autoeat") and etime >= get_float("cooldown", 0.5) and autoeat.get_hunger() < get_float("hunger", 9) then
|
||||
etime = 0
|
||||
autoeat.eat()
|
||||
end
|
||||
end)
|
||||
local function get_hud()
|
||||
local player = minetest.localplayer
|
||||
local def
|
||||
local i = -1
|
||||
if not player then minetest.after(5,get_hud) return end
|
||||
repeat
|
||||
i = i + 1
|
||||
def = player:hud_get(i)
|
||||
until not def or def.text == "hbhunger_icon.png"
|
||||
if def then
|
||||
hud_id = i
|
||||
end
|
||||
end
|
||||
minetest.after(15,get_hud )
|
||||
|
||||
minetest.register_cheat("AutoEat", "Player", "autoeat")
|
|
@ -0,0 +1,4 @@
|
|||
name = autoeat
|
||||
author = Fleckenstein
|
||||
description = Automatically eat when a certain hunger is reached (MineClone2).
|
||||
optional_depends = autodupe
|
|
@ -0,0 +1,3 @@
|
|||
autoeat (AutoEat) bool false
|
||||
autoeat_cooldown (AutoEat cooldown) float 0.5
|
||||
autoeat_hunger (AutoEat hunger) float 9.0
|
|
@ -0,0 +1,732 @@
|
|||
-- autofly by cora
|
||||
-- gui shit shamelessly stolen from advmarkers
|
||||
-- https://git.minetest.land/luk3yx/advmarkers-csm
|
||||
--[[
|
||||
PATCHING MINETEST: (for autoaim)
|
||||
in l_localplayer.h add:
|
||||
static int l_set_yaw(lua_State *L);
|
||||
static int l_set_pitch(lua_State *L);
|
||||
|
||||
in l_localplayer.cpp add:
|
||||
int LuaLocalPlayer::l_set_yaw(lua_State *L)
|
||||
{
|
||||
LocalPlayer *player = getobject(L, 1);
|
||||
f32 p = (float) luaL_checkinteger(L, 2);
|
||||
player->setYaw(p);
|
||||
g_game->cam_view.camera_yaw = p;
|
||||
g_game->cam_view_target.camera_yaw = p;
|
||||
player->setYaw(p);
|
||||
return 0;
|
||||
}
|
||||
int LuaLocalPlayer::l_set_pitch(lua_State *L)
|
||||
{
|
||||
LocalPlayer *player = getobject(L, 1);
|
||||
f32 p = (float) luaL_checkinteger(L, 2);
|
||||
player->setPitch(p);
|
||||
g_game->cam_view.camera_pitch = p;
|
||||
g_game->cam_view_target.camera_pitch = p;
|
||||
player->setPitch(p);
|
||||
return 0;
|
||||
}
|
||||
in src/client/game.h, below class Game { public: add:
|
||||
CameraOrientation cam_view = {0};
|
||||
CameraOrientation cam_view_target = { 0 };
|
||||
|
||||
from src/client/game.cpp remove
|
||||
CameraOrientation cam_view = {0};
|
||||
CameraOrientation cam_view_target = { 0 };
|
||||
|
||||
--]]
|
||||
|
||||
-- Chat commands:
|
||||
-- .wa x,y,z name - add waypoint with coords and name
|
||||
-- .wah - quickadd this location (name will be time and date)
|
||||
-- .wp - open the selection menu
|
||||
-- .cls - remove hud
|
||||
|
||||
autofly = {}
|
||||
wps={}
|
||||
|
||||
|
||||
local landing_distance=5
|
||||
local speed=0;
|
||||
local ltime=0
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
local oldpm=false
|
||||
local lpos={x=0,y=0,z=0}
|
||||
local info=minetest.get_server_info()
|
||||
local stprefix="autofly-".. info['address'] .. '-'
|
||||
--local stprefix="autofly-"
|
||||
local hud_wps={}
|
||||
autofly.flying=false
|
||||
autofly.cruiseheight = 30
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
dofile(modpath .. "/wpforms.lua")
|
||||
dofile(modpath .. "/pathfly.lua")
|
||||
|
||||
local hud_wp
|
||||
local hud_info
|
||||
-- /COMMON
|
||||
local pos_to_string = ws.pos_to_string
|
||||
local string_to_pos = ws.string_to_pos
|
||||
|
||||
|
||||
function autofly.get2ddst(pos1,pos2)
|
||||
return vector.distance({x=pos1.x,y=0,z=pos1.z},{x=pos2.x,y=0,z=pos2.z})
|
||||
end
|
||||
|
||||
local last_sprint = false
|
||||
local hud_ah=nil
|
||||
|
||||
|
||||
|
||||
function autofly.update_ah()
|
||||
local pos=vector.new(0,0,0)
|
||||
local ppos=minetest.localplayer:get_pos()
|
||||
local yaw=math.floor(minetest.localplayer:get_yaw())
|
||||
|
||||
local theta =(yaw * math.pi / 180)
|
||||
pos.x= math.floor( 100 * math.cos(theta) )
|
||||
pos.z= math.floor( 100 * math.sin(theta) )
|
||||
pos=vector.add(ppos,pos)
|
||||
pos.y=ppos.y
|
||||
local nname=pos_to_string(pos).."\n"..yaw.."\n"..'__________________________________________________________________________________________________________________________________________________'
|
||||
if hud_ah then
|
||||
minetest.display_chat_message(pos.x..","..pos.z)
|
||||
minetest.localplayer:hud_change(hud_ah, 'world_pos', pos)
|
||||
minetest.localplayer:hud_change(hud_ah, 'name', nname)
|
||||
else
|
||||
hud_ah = minetest.localplayer:hud_add({
|
||||
hud_elem_type = 'waypoint',
|
||||
name = nname,
|
||||
title = pos_to_string(pos),
|
||||
text = '',
|
||||
number = 0x00ff00,
|
||||
world_pos = pos,
|
||||
precision = 0,
|
||||
width = 1000
|
||||
})
|
||||
end
|
||||
end
|
||||
minetest.register_globalstep(function()
|
||||
|
||||
if not minetest.localplayer then return end
|
||||
-- autofly.update_ah()
|
||||
end)
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if not minetest.localplayer then return end
|
||||
|
||||
autofly.axissnap()
|
||||
if minetest.settings:get_bool("autosprint") or (minetest.settings:get_bool("continuous_forward") and minetest.settings:get_bool("autofsprint")) then
|
||||
core.set_keypress("special1", true)
|
||||
last_sprint = true
|
||||
elseif last_sprint then
|
||||
core.set_keypress("special1", false)
|
||||
last_sprint = false
|
||||
end
|
||||
if not autofly.flying then autofly.set_hud_info("")
|
||||
else
|
||||
autofly.set_hud_info("")
|
||||
local pos = autofly.last_coords
|
||||
if pos then
|
||||
local dst = vector.distance(pos,minetest.localplayer:get_pos())
|
||||
local etatime=-1
|
||||
if not (speed == 0) then etatime = ws.round2(dst / speed / 60,2) end
|
||||
autofly.etatime=etatime
|
||||
autofly.set_hud_info(autofly.last_name .. "\n" .. pos_to_string(pos) .. "\n" .. "ETA" .. etatime .. " mins")
|
||||
local pm=minetest.settings:get_bool('pitch_move')
|
||||
local hdst=autofly.get2ddst(pos,minetest.localplayer:get_pos())
|
||||
if pm then hdst=vector.distance(pos,ws.dircoord(0,0,0)) end
|
||||
if autofly.flying and hdst < landing_distance then
|
||||
autofly.arrived()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not minetest.settings:get_bool("freecam") and autofly.flying and (minetest.settings:get_bool('afly_autoaim')) then
|
||||
autofly.aim(autofly.last_coords)
|
||||
end
|
||||
|
||||
if ( os.time() < ltime + 1 ) then return end
|
||||
ltime=os.time()
|
||||
if lpos then
|
||||
local dst=vector.distance(minetest.localplayer:get_pos(),lpos)
|
||||
speed=ws.round2(dst,1)
|
||||
autofly.speed=speed
|
||||
end
|
||||
lpos=minetest.localplayer:get_pos()
|
||||
autofly.cruise()
|
||||
end)
|
||||
|
||||
function autofly.get_speed()
|
||||
return speed
|
||||
end
|
||||
|
||||
|
||||
function autofly.set_hud_wp(pos, title)
|
||||
if hud_wp then
|
||||
minetest.localplayer:hud_remove(hud_wp)
|
||||
end
|
||||
pos = string_to_pos(pos)
|
||||
hud_wp=nil
|
||||
if not pos then return end
|
||||
if not title then
|
||||
title = pos.x .. ', ' .. pos.y .. ', ' .. pos.z
|
||||
end
|
||||
autofly.last_name=title
|
||||
if hud_wp then
|
||||
minetest.localplayer:hud_change(hud_wp, 'name', title)
|
||||
minetest.localplayer:hud_change(hud_wp, 'world_pos', pos)
|
||||
else
|
||||
hud_wp = minetest.localplayer:hud_add({
|
||||
hud_elem_type = 'waypoint',
|
||||
name = title,
|
||||
text = 'm',
|
||||
number = 0x00ff00,
|
||||
world_pos = pos
|
||||
})
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local hud_info
|
||||
function autofly.get_quad()
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local quad=""
|
||||
|
||||
if lp.z < 0 then quad="South"
|
||||
else quad="North" end
|
||||
|
||||
if lp.x < 0 then quad=quad.."-west"
|
||||
else quad=quad.."-east" end
|
||||
|
||||
return quad
|
||||
end
|
||||
|
||||
function autofly.get_wdir()
|
||||
local qd=autofly.get_quad()
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function autofly.get_local_name()
|
||||
local ww=autofly.getwps()
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local odst=500;
|
||||
local rt=false
|
||||
for k,v in pairs(ww) do
|
||||
local lwp=autofly.get_waypoint(v)
|
||||
if type(lwp) == 'table' then
|
||||
local dst=vector.distance(lp,lwp)
|
||||
if dst < 500 then
|
||||
if dst < odst then
|
||||
odst=dst
|
||||
rt=v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not rt then rt=autofly.get_quad() end
|
||||
return rt
|
||||
end
|
||||
|
||||
|
||||
local function countents()
|
||||
local obj = minetest.localplayer.get_nearby_objects(10000)
|
||||
return #obj
|
||||
end
|
||||
|
||||
|
||||
function autofly.set_hud_info(text)
|
||||
if not minetest.localplayer then return end
|
||||
if type(text) ~= "string" then return end
|
||||
local dir=ws.getdir()
|
||||
local ddir=""
|
||||
if dir == "north" then
|
||||
ddir="north(+z)"
|
||||
elseif dir == "east" then
|
||||
ddir="east(+x)"
|
||||
elseif dir == "south" then
|
||||
ddir="south(-z)"
|
||||
elseif dir == "west" then
|
||||
ddir="west(-x)"
|
||||
end
|
||||
local lp=minetest.localplayer
|
||||
local vspeed=lp:get_velocity()
|
||||
local ttext=text.."\nSpeed: "..speed.."n/s\n"
|
||||
..ws.round2(vspeed.x,2) ..','
|
||||
..ws.round2(vspeed.y,2) ..','
|
||||
..ws.round2(vspeed.z,2) .."\n"
|
||||
.."Yaw:"..ws.round2(lp:get_yaw(),2).."° Pitch:" ..ws.round2(lp:get_pitch(),2).."° "
|
||||
if turtle then ttext=ttext..ddir end
|
||||
if minetest.settings:get_bool('afly_shownames') then
|
||||
ttext=ttext.."\n"..autofly.get_local_name() .."\nEntities: " .. countents()
|
||||
end
|
||||
if hud_info then
|
||||
minetest.localplayer:hud_change(hud_info,'text',ttext)
|
||||
else
|
||||
hud_info = minetest.localplayer:hud_add({
|
||||
hud_elem_type = 'text',
|
||||
name = "Flight Info",
|
||||
text = ttext,
|
||||
number = 0x00ff00,
|
||||
direction = 0,
|
||||
position = {x=0,y=0.8},
|
||||
alignment ={x=1,y=1},
|
||||
offset = {x=0, y=0}
|
||||
})
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function autofly.display(pos,name)
|
||||
if name == nil then name=pos_to_string(pos) end
|
||||
local pos=string_to_pos(pos)
|
||||
autofly.set_hud_wp(pos, name)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function autofly.display_waypoint(name)
|
||||
local pos=name
|
||||
if type(name) ~= 'table' then pos=autofly.get_waypoint(name) end
|
||||
autofly.last_name = name
|
||||
--autofly.last_coords = pos
|
||||
autofly.set_hud_info(name)
|
||||
autofly.aim(autofly.last_coords)
|
||||
autofly.display(pos,name)
|
||||
return true
|
||||
end
|
||||
|
||||
function autofly.goto_waypoint(name)
|
||||
local wp=autofly.get_waypoint(name)
|
||||
autofly.goto(wp)
|
||||
autofly.last_name=name
|
||||
autofly.display_waypoint(autofly.last_name)
|
||||
return true
|
||||
end
|
||||
|
||||
function autofly.goto(pos)
|
||||
minetest.settings:set_bool("free_move",true)
|
||||
minetest.settings:set_bool("continuous_forward",true)
|
||||
if minetest.settings:get_bool("afly_sprint") then
|
||||
minetest.settings:set_bool("autofsprint",true)
|
||||
minetest.settings:set_bool("autoeat_timed",true)
|
||||
end
|
||||
minetest.settings:set_bool("afly_autoaim",true)
|
||||
autofly.last_coords = pos
|
||||
autofly.last_name = minetest.pos_to_string(pos)
|
||||
autofly.aim(autofly.last_coords)
|
||||
autofly.flying=true
|
||||
autofly.set_hud_wp(autofly.last_coords, autofly.last_name)
|
||||
return true
|
||||
end
|
||||
|
||||
function autofly.fly3d(pos)
|
||||
minetest.settings:set_bool("pitch_move",true)
|
||||
autofly.goto(pos)
|
||||
end
|
||||
|
||||
function autofly.fly2d(pos)
|
||||
minetest.settings:set_bool("pitch_move",false)
|
||||
autofly.goto(pos)
|
||||
end
|
||||
|
||||
function autofly.arrived()
|
||||
if not autofly.flying then return end
|
||||
minetest.settings:set("continuous_forward", "false")
|
||||
minetest.settings:set_bool("autofsprint",false)
|
||||
minetest.settings:set_bool("pitch_move",oldpm)
|
||||
minetest.settings:set_bool("afly_autoaim",false)
|
||||
minetest.settings:set_bool("autoeat_timed",false)
|
||||
autofly.set_hud_info("Arrived!")
|
||||
autofly.flying = false
|
||||
minetest.sound_play({name = "default_alert", gain = 1.0})
|
||||
end
|
||||
|
||||
local cruise_wason=false
|
||||
local nfctr=0
|
||||
|
||||
|
||||
function autofly.cruise()
|
||||
if not minetest.settings:get_bool('afly_cruise') then
|
||||
if cruise_wason then
|
||||
cruise_wason=false
|
||||
core.set_keypress("jump",false)
|
||||
core.set_keypress("sneak",false)
|
||||
end
|
||||
return end
|
||||
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local pos1 = vector.add(lp,{x=16,y=100,z=16})
|
||||
local pos2 = vector.add(lp,{x=-16,y=-100,z=-16})
|
||||
local nds=minetest.find_nodes_in_area_under_air(pos1, pos2, nlist.get_mclnodes())
|
||||
local y=0
|
||||
local found=false
|
||||
|
||||
|
||||
for k,v in ipairs(nds) do
|
||||
local nd = minetest.get_node_or_nil(v)
|
||||
if nd ~= nil and nd.name ~= "air" then
|
||||
if v.y > y then
|
||||
y=v.y
|
||||
found=true
|
||||
end
|
||||
end
|
||||
end
|
||||
if (autofly.cruiseheight ~= nil) then y=y+autofly.cruiseheight end
|
||||
local diff = math.ceil(lp.y - y)
|
||||
|
||||
if not cruise_wason then --initially set the cruiseheight to the current value above ground
|
||||
-- if not found then return end --wait with activation til a ground node has been found.
|
||||
local clr,nnd=minetest.line_of_sight(lp,vector.add(lp,{x=1,y=-200,z=1}))
|
||||
if not clr then diff = math.ceil(lp.y - nnd.y)
|
||||
elseif not found then return end
|
||||
if diff < 1 then autofly.cruiseheight = 20
|
||||
else autofly.cruiseheight = diff end
|
||||
|
||||
cruise_wason=true
|
||||
minetest.display_chat_message("cruise mode activated. target height set to " .. diff .. " nodes above ground.")
|
||||
end
|
||||
|
||||
if not found then
|
||||
if nfctr<20 then nfctr = nfctr + 1 return end
|
||||
--minetest.display_chat_message("no nodes found for 20 iterations. lowering altitude.")
|
||||
nfctr=0
|
||||
minetest.settings:set_bool("free_move",false)
|
||||
core.set_keypress("jump",false)
|
||||
core.set_keypress("sneak",false)
|
||||
return
|
||||
end
|
||||
|
||||
local tolerance = 1
|
||||
if diff < -tolerance then
|
||||
minetest.settings:set_bool("free_move",true)
|
||||
core.set_keypress("jump",true)
|
||||
core.set_keypress("sneak",false)
|
||||
--minetest.display_chat_message("too low: " .. y)
|
||||
elseif diff > tolerance * 10 then
|
||||
core.set_keypress("jump",false)
|
||||
core.set_keypress("sneak",true)
|
||||
minetest.settings:set_bool("free_move",false)
|
||||
--minetest.display_chat_message("too high: " .. y)
|
||||
elseif diff > tolerance then
|
||||
core.set_keypress("jump",false)
|
||||
core.set_keypress("sneak",true)
|
||||
else
|
||||
minetest.settings:set_bool("free_move",true)
|
||||
core.set_keypress("jump",false)
|
||||
core.set_keypress("sneak",false)
|
||||
--minetest.display_chat_message("target height reached: " .. y)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function autofly.aim(tpos)
|
||||
return ws.aim(tpos)
|
||||
end
|
||||
|
||||
function autofly.autotp(tpname)
|
||||
if minetest.localplayer == nil then autofly.autotp(tpname) end
|
||||
local tpos=nil
|
||||
if tpname == nil then
|
||||
tpos = autofly.get_waypoint('AUTOTP')
|
||||
elseif type(tpname) == "table" then
|
||||
tpos = tpname
|
||||
else
|
||||
tpos=autofly.get_waypoint(tpname)
|
||||
end
|
||||
if tpos == nil then return end
|
||||
local lp=minetest.localplayer
|
||||
local dst=vector.distance(lp:get_pos(),tpos)
|
||||
if (dst < 300) then
|
||||
minetest.sound_play({name = "default_alert", gain = 3.0})
|
||||
autofly.delete_waypoint('AUTOTP')
|
||||
return true
|
||||
end
|
||||
autofly.set_waypoint(tpos,'AUTOTP')
|
||||
local boat_found=false
|
||||
for k, v in ipairs(lp.get_nearby_objects(4)) do
|
||||
local txt = v:get_item_textures()
|
||||
if ( txt:find('mcl_boats_texture')) then
|
||||
boat_found=true
|
||||
minetest.display_chat_message("boat found. entering and tping to "..minetest.pos_to_string(autofly.get_waypoint('AUTOTP')))
|
||||
autofly.aim(vector.add(v:get_pos(),{x=0,y=-1.5,z=0}))
|
||||
minetest.after("0.2",function()
|
||||
minetest.interact("place") end)
|
||||
minetest.after("1.5",function()
|
||||
autofly.warpae('AUTOTP')
|
||||
end)
|
||||
return true
|
||||
end
|
||||
end
|
||||
if not boat_found then
|
||||
minetest.display_chat_message("no boat found. trying again in 5.")
|
||||
minetest.after("5.0",function() autofly.autotp(tpname) end)
|
||||
return end
|
||||
end
|
||||
|
||||
|
||||
|
||||
autofly.register_transport('Fly3D',function(pos,name) autofly.fly3d(pos,name) end)
|
||||
autofly.register_transport('Fly2D',function(pos,name) autofly.fly2d(pos,name) end)
|
||||
autofly.register_transport('wrp',function(pos,name) autofly.warp(name) end)
|
||||
--autofly.register_transport('atp',function(pos,name) autofly.autotp(name) end)
|
||||
|
||||
function autofly.axissnap()
|
||||
if not minetest.settings:get_bool('afly_snap') then return end
|
||||
if minetest.settings:get_bool("freecam") then return end
|
||||
local y=minetest.localplayer:get_yaw()
|
||||
local yy=nil
|
||||
if ( y < 45 or y > 315 ) then
|
||||
yy=0
|
||||
elseif (y < 135) then
|
||||
yy=90
|
||||
elseif (y < 225 ) then
|
||||
yy=180
|
||||
elseif ( y < 315 ) then
|
||||
yy=270
|
||||
end
|
||||
if yy ~= nil then
|
||||
minetest.localplayer:set_yaw(yy)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_death(function()
|
||||
if minetest.localplayer then
|
||||
local name = 'Death waypoint'
|
||||
local pos = minetest.localplayer:get_pos()
|
||||
autofly.last_coords = pos
|
||||
autofly.last_name = name
|
||||
autofly.set_waypoint(pos,name)
|
||||
autofly.display(pos,name)
|
||||
end
|
||||
end)
|
||||
|
||||
local function get_dimension(pos)
|
||||
if pos.y > -65 then return "overworld"
|
||||
elseif pos.y > -8000 then return "void"
|
||||
elseif pos.y > -27000 then return "end"
|
||||
elseif pos.y >29000 then return "void"
|
||||
elseif pos.y >31000 then return "nether"
|
||||
else return "void"
|
||||
end
|
||||
end
|
||||
|
||||
function autofly.warp(name)
|
||||
local pos=autofly.get_waypoint(name)
|
||||
if pos then
|
||||
if get_dimension(pos) == "void" then return false end
|
||||
minetest.localplayer:set_pos(pos)
|
||||
return true
|
||||
end
|
||||
end
|
||||
function autofly.warpae(name)
|
||||
local s, m = autofly.warp(name)
|
||||
if s then
|
||||
minetest.disconnect()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function autofly.getwps()
|
||||
local wp={}
|
||||
for name, _ in pairs(storage:to_table().fields) do
|
||||
if name:sub(1, string.len(stprefix)) == stprefix then
|
||||
table.insert(wp, name:sub(string.len(stprefix)+1))
|
||||
end
|
||||
end
|
||||
table.sort(wp)
|
||||
return wp
|
||||
end
|
||||
|
||||
|
||||
|
||||
function autofly.impfromsrv(srv,sel)
|
||||
local srvstr="autofly-".. srv .. '-'
|
||||
for name, _ in pairs(storage:to_table().fields) do
|
||||
if name:sub(1, string.len(srvstr)) == srvstr then
|
||||
local name=name:sub(string.len(srvstr)+1)
|
||||
if not sel or ( sel and name:sub(1, string.len(sel)) == sel ) then
|
||||
local pos=string_to_pos(storage:get_string(srvstr .. tostring(name)))
|
||||
autofly.set_waypoint(pos,name)
|
||||
end
|
||||
end
|
||||
end
|
||||
return wp
|
||||
end
|
||||
|
||||
function autofly.set_waypoint(pos, name)
|
||||
pos = pos_to_string(pos)
|
||||
if not pos then return end
|
||||
storage:set_string(stprefix .. tostring(name), pos)
|
||||
return true
|
||||
end
|
||||
|
||||
function autofly.delete_waypoint(name)
|
||||
storage:set_string(stprefix .. tostring(name), '')
|
||||
end
|
||||
|
||||
function autofly.get_waypoint(name)
|
||||
return string_to_pos(storage:get_string(stprefix .. tostring(name)))
|
||||
end
|
||||
|
||||
function autofly.rename_waypoint(oldname, newname)
|
||||
oldname, newname = tostring(oldname), tostring(newname)
|
||||
local pos = autofly.get_waypoint(oldname)
|
||||
if not pos or not autofly.set_waypoint(pos, newname) then return end
|
||||
if oldname ~= newname then
|
||||
autofly.delete_waypoint(oldname)
|
||||
end
|
||||
return true
|
||||
end
|
||||
local function log(level, message)
|
||||
minetest.log(level, ('[%s] %s'):format(mod_name, message))
|
||||
end
|
||||
function autofly.dumptolog()
|
||||
local wp=autofly.getwps()
|
||||
for name, _ in pairs(wp) do
|
||||
--local lname=name:sub(string.len(stprefix)+1)
|
||||
-- local ppos=string_to_pos(storage:get_string(tostring(name)))
|
||||
if ppos then
|
||||
log('action',name .. ' :: ')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.after("5.0",function()
|
||||
if autofly.get_waypoint('AUTOTP') ~= nil then autofly.autotp(nil) end
|
||||
end)
|
||||
|
||||
|
||||
math.randomseed(os.time())
|
||||
|
||||
local randflying = false
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if randflying and not autofly.flying then
|
||||
local x = math.random(-31000, 31000)
|
||||
local y = math.random(2000, 31000)
|
||||
local z = math.random(-31000, 31000)
|
||||
|
||||
autofly.goto({x = x, y = y, z = z})
|
||||
end
|
||||
end)
|
||||
|
||||
local function randfly()
|
||||
if not randflying then
|
||||
randflying = true
|
||||
local lp = minetest.localplayer:get_pos()
|
||||
autofly.goto(turtle.coord(lp.x, 6000, lp.z))
|
||||
else
|
||||
randflying = false
|
||||
autofly.arrived()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
minetest.register_chatcommand('waypoints', {
|
||||
params = '',
|
||||
description = 'Open the autofly GUI',
|
||||
func = function(param) autofly.display_formspec() end
|
||||
})
|
||||
|
||||
ws.register_chatcommand_alias('waypoints','wp', 'wps', 'waypoint')
|
||||
|
||||
-- Add a waypoint
|
||||
minetest.register_chatcommand('add_waypoint', {
|
||||
params = '<pos / "here" / "there"> <name>',
|
||||
description = 'Adds a waypoint.',
|
||||
func = function(param)
|
||||
local s, e = param:find(' ')
|
||||
if not s or not e then
|
||||
return false, 'Invalid syntax! See .help add_mrkr for more info.'
|
||||
end
|
||||
local pos = param:sub(1, s - 1)
|
||||
local name = param:sub(e + 1)
|
||||
if not pos then
|
||||
return false, err
|
||||
end
|
||||
if not name or #name < 1 then
|
||||
return false, 'Invalid name!'
|
||||
end
|
||||
return autofly.set_waypoint(pos, name), 'Done!'
|
||||
end
|
||||
})
|
||||
ws.register_chatcommand_alias('add_waypoint','wa', 'add_wp')
|
||||
|
||||
|
||||
minetest.register_chatcommand('add_waypoint_here', {
|
||||
params = 'name',
|
||||
description = 'marks the current position',
|
||||
func = function(param)
|
||||
local name = os.date("%Y-%m-%d %H:%M:%S")
|
||||
local pos = minetest.localplayer:get_pos()
|
||||
return autofly.set_waypoint(pos, name), 'Done!'
|
||||
end
|
||||
})
|
||||
ws.register_chatcommand_alias('add_waypoint_here', 'wah', 'add_wph')
|
||||
|
||||
minetest.register_chatcommand('clear_waypoint', {
|
||||
params = '',
|
||||
description = 'Hides the displayed waypoint.',
|
||||
func = function(param)
|
||||
if autofly.flying then autofly.flying=false end
|
||||
if hud_wp then
|
||||
minetest.localplayer:hud_remove(hud_wp)
|
||||
hud_wp = nil
|
||||
return true, 'Hidden the currently displayed waypoint.'
|
||||
elseif not minetest.localplayer.hud_add then
|
||||
minetest.run_server_chatcommand('clrmrkr')
|
||||
return
|
||||
elseif not hud_wp then
|
||||
return false, 'No waypoint is currently being displayed!'
|
||||
end
|
||||
for k,v in wps do
|
||||
minetest.localplayer:hud_remove(v)
|
||||
table.remove(k)
|
||||
end
|
||||
|
||||
end,
|
||||
})
|
||||
ws.register_chatcommand_alias('clear_waypoint', 'cwp','cls')
|
||||
|
||||
minetest.register_chatcommand('autotp', {
|
||||
params = 'position',
|
||||
description = 'autotp',
|
||||
func = function(param)
|
||||
autofly.autotp(minetest.string_to_pos(param))
|
||||
end
|
||||
})
|
||||
ws.register_chatcommand_alias('autotp', 'atp')
|
||||
|
||||
minetest.register_chatcommand('wpdisplay', {
|
||||
params = 'position name',
|
||||
description = 'display waypoint',
|
||||
func = function(pos,name)
|
||||
autofly.display(pos,name)
|
||||
end
|
||||
})
|
||||
ws.register_chatcommand_alias('wpdisplay', 'wpd')
|
||||
|
||||
|
||||
|
||||
minetest.register_chatcommand("randfly", {
|
||||
description = "Randomly fly up high (toggle).",
|
||||
func = randfly
|
||||
})
|
||||
|
||||
|
||||
minetest.register_cheat("Aim", "Autofly", "afly_autoaim")
|
||||
minetest.register_cheat("AxisSnap", "Autofly", "afly_snap")
|
||||
minetest.register_cheat("Cruise", "Autofly", "afly_cruise")
|
||||
minetest.register_cheat("Sprint", "Autofly", "afly_sprint")
|
||||
minetest.register_cheat("ShowNames", "Autofly", "afly_shownames")
|
||||
minetest.register_cheat("Waypoints", "Autofly", autofly.display_formspec)
|
|
@ -0,0 +1,3 @@
|
|||
name = autofly
|
||||
author = cora
|
||||
description = autonomous flight
|
|
@ -0,0 +1,35 @@
|
|||
local function get_3dpos_from_yaw_and_pitch(r,yaw,pitch)
|
||||
local tg=vector.new(0,0,0)
|
||||
tg.x= r * math.sin(yaw)
|
||||
tg.y= r * math.sin(pitch)
|
||||
tg.z= r * math.cos(yaw)
|
||||
return tg
|
||||
end
|
||||
local nexttarget=vector.new(0,0,0)
|
||||
|
||||
local sdst=40
|
||||
|
||||
function autofly.pathfind(coords)
|
||||
local lp=minetest.localplayer
|
||||
autofly.aim(coords)
|
||||
local yaw=lp:get_yaw()
|
||||
local pitch=lp:get_pitch()
|
||||
local ltgt=vector.add(lp:get_pos(),get_3dpos_from_yaw_and_pitch(sdst,yaw,pitch))
|
||||
local tgt=vector.new(0,0,0)
|
||||
|
||||
if not minetest.line_of_sight(lp:get_pos(), ltgt) then
|
||||
local path=minetest.find_path(lp:get_pos(),ltgt,sdst*2,100,100,'Dijkstra')
|
||||
if not path then
|
||||
minetest.display_chat_message("no path found.")
|
||||
return
|
||||
end
|
||||
tgt=vector.add(path[1],vector.new(0,2,0))
|
||||
if vector.distance(lp:get_pos(),tgt) < 6 then
|
||||
tgt=vector.add(path[2],vector.new(0,2,0))
|
||||
end
|
||||
else
|
||||
tgt=ltgt
|
||||
end
|
||||
autofly.aim(tgt)
|
||||
autofly.goto(tgt)
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
afly_autoaim (Autoaim) bool false
|
||||
afly_softlanding (Soft Landing) bool true
|
||||
afly_sprint (Sprint while flying) bool true
|
|
@ -0,0 +1,251 @@
|
|||
|
||||
|
||||
|
||||
-- ADVMARKERS Stuff
|
||||
-- Get the waypoints formspec
|
||||
local formspec_list = {}
|
||||
local selected_name = false
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
local wpr=false;
|
||||
local twpname=nil
|
||||
local info=minetest.get_server_info()
|
||||
local stprefix="autofly-".. info['address'] .. '-'
|
||||
|
||||
autofly = {}
|
||||
wps={}
|
||||
autofly.registered_transports={}
|
||||
local tspeed = 20 -- speed in blocks per second
|
||||
local speed=0;
|
||||
local ltime=0
|
||||
function autofly.register_transport(name,func)
|
||||
table.insert(autofly.registered_transports,{name=name,func=func})
|
||||
end
|
||||
function autofly.display_formspec()
|
||||
local formspec = 'size[6.25,9]' ..
|
||||
'label[0,0;Waypoint list]' ..
|
||||
|
||||
'button_exit[0,7.5;1,0.5;display;Show]' ..
|
||||
'button[3.625,7.5;1.3,0.5;rename;Rename]' ..
|
||||
'button[4.9375,7.5;1.3,0.5;delete;Delete]'
|
||||
local sp=0
|
||||
for k,v in pairs(autofly.registered_transports) do
|
||||
formspec=formspec..'button_exit['..sp..',8.5;1,0.5;'..v.name..';'..v.name..']'
|
||||
sp=sp+0.8
|
||||
end
|
||||
|
||||
formspec=formspec..'textlist[0,0.75;6,6;marker;'
|
||||
local selected = 1
|
||||
formspec_list = {}
|
||||
|
||||
local waypoints = autofly.getwps()
|
||||
|
||||
|
||||
for id, name in ipairs(waypoints) do
|
||||
if id > 1 then
|
||||
formspec = formspec .. ','
|
||||
end
|
||||
if not selected_name then
|
||||
selected_name = name
|
||||
end
|
||||
if name == selected_name then
|
||||
selected = id
|
||||
end
|
||||
formspec_list[#formspec_list + 1] = name
|
||||
formspec = formspec .. '##' .. minetest.formspec_escape(name)
|
||||
end
|
||||
|
||||
formspec = formspec .. ';' .. tostring(selected) .. ']'
|
||||
|
||||
if selected_name then
|
||||
local pos = autofly.get_waypoint(selected_name)
|
||||
if pos then
|
||||
pos = minetest.formspec_escape(tostring(pos.x) .. ', ' ..
|
||||
tostring(pos.y) .. ', ' .. tostring(pos.z))
|
||||
pos = 'Waypoint position: ' .. pos
|
||||
formspec = formspec .. 'label[0,6.75;' .. pos .. ']'
|
||||
end
|
||||
else
|
||||
-- Draw over the buttons
|
||||
formspec = formspec .. 'button_exit[0,7.5;5.25,0.5;quit;Close dialog]' ..
|
||||
'label[0,6.75;No waypoints. Add one with ".wa".]'
|
||||
end
|
||||
|
||||
-- Display the formspec
|
||||
return minetest.show_formspec('autofly-csm', formspec)
|
||||
end
|
||||
|
||||
minetest.register_on_formspec_input(function(formname, fields)
|
||||
if formname == 'autofly-ignore' then
|
||||
return true
|
||||
elseif formname ~= 'autofly-csm' then
|
||||
return
|
||||
end
|
||||
local name = false
|
||||
if fields.marker then
|
||||
local event = minetest.explode_textlist_event(fields.marker)
|
||||
if event.index then
|
||||
name = formspec_list[event.index]
|
||||
end
|
||||
else
|
||||
name = selected_name
|
||||
end
|
||||
|
||||
if name then
|
||||
for k,v in pairs(autofly.registered_transports) do
|
||||
if fields[v.name] then
|
||||
if not v.func(autofly.get_waypoint(name),name) then
|
||||
minetest.display_chat_message('Error with '..v.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
if fields.display then
|
||||
if not autofly.display_waypoint(name) then
|
||||
minetest.display_chat_message('Error displaying waypoint!')
|
||||
end
|
||||
elseif fields.goto then
|
||||
if not autofly.goto_waypoint(name) then
|
||||
minetest.display_chat_message('Error flying to waypoint!')
|
||||
end
|
||||
elseif fields.warp then
|
||||
if not autofly.warp(name) then
|
||||
minetest.display_chat_message('warp error')
|
||||
end
|
||||
elseif fields.autotp then
|
||||
if not autofly.autotp(name) then
|
||||
minetest.display_chat_message('warpandexit error')
|
||||
end
|
||||
elseif fields.itp then
|
||||
if incremental_tp then
|
||||
incremental_tp.tp(autofly.get_waypoint(name),1)
|
||||
end
|
||||
elseif fields.jitp then
|
||||
if incremental_tp then
|
||||
incremental_tp.tp(autofly.get_waypoint(name),0.5,0.4)
|
||||
end
|
||||
elseif fields.rename then
|
||||
minetest.show_formspec('autofly-csm', 'size[6,3]' ..
|
||||
'label[0.35,0.2;Rename waypoint]' ..
|
||||
'field[0.3,1.3;6,1;new_name;New name;' ..
|
||||
minetest.formspec_escape(name) .. ']' ..
|
||||
'button[0,2;3,1;cancel;Cancel]' ..
|
||||
'button[3,2;3,1;rename_confirm;Rename]')
|
||||
elseif fields.rename_confirm then
|
||||
if fields.new_name and #fields.new_name > 0 then
|
||||
if autofly.rename_waypoint(name, fields.new_name) then
|
||||
selected_name = fields.new_name
|
||||
else
|
||||
minetest.display_chat_message('Error renaming waypoint!')
|
||||
end
|
||||
autofly.display_formspec()
|
||||
else
|
||||
minetest.display_chat_message(
|
||||
'Please enter a new name for the marker.'
|
||||
)
|
||||
end
|
||||
elseif fields.delete then
|
||||
minetest.show_formspec('autofly-csm', 'size[6,2]' ..
|
||||
'label[0.35,0.25;Are you sure you want to delete this waypoint?]' ..
|
||||
'button[0,1;3,1;cancel;Cancel]' ..
|
||||
'button[3,1;3,1;delete_confirm;Delete]')
|
||||
elseif fields.delete_confirm then
|
||||
autofly.delete_waypoint(name)
|
||||
selected_name = false
|
||||
autofly.display_formspec()
|
||||
elseif fields.cancel then
|
||||
autofly.display_formspec()
|
||||
elseif name ~= selected_name then
|
||||
selected_name = name
|
||||
autofly.display_formspec()
|
||||
end
|
||||
elseif fields.display or fields.delete then
|
||||
minetest.display_chat_message('Please select a waypoint.')
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
|
||||
-- Export waypoints
|
||||
function autofly.export(raw)
|
||||
local s = storage:to_table().fields
|
||||
if raw == 'M' then
|
||||
s = minetest.compress(minetest.serialize(s))
|
||||
s = 'M' .. minetest.encode_base64(s)
|
||||
elseif not raw then
|
||||
s = minetest.compress(minetest.write_json(s))
|
||||
s = 'J' .. minetest.encode_base64(s)
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
-- Allow string exporting
|
||||
minetest.register_chatcommand('wpexp', {
|
||||
params = '[old]',
|
||||
description = 'Exports an autofly string containing all your pois.',
|
||||
func = function(param)
|
||||
local export
|
||||
if param == 'old' then
|
||||
export = autofly.export('M')
|
||||
else
|
||||
export = autofly.export()
|
||||
end
|
||||
minetest.show_formspec('autofly-ignore',
|
||||
'field[_;Your waypoint export string;' ..
|
||||
minetest.formspec_escape(export) .. ']')
|
||||
end
|
||||
})
|
||||
|
||||
--register_chatcommand_alias('wpexp', 'wp_export', 'waypoint_export')
|
||||
|
||||
-- String importing
|
||||
minetest.register_chatcommand('wpimp', {
|
||||
params = '<autofly string>',
|
||||
description = 'Imports an autofly string. This will not overwrite ' ..
|
||||
'existing pois that have the same name.',
|
||||
func = function(param)
|
||||
if autofly.import(param) then
|
||||
return true, 'Waypoints imported!'
|
||||
else
|
||||
return false, 'Invalid autofly string!'
|
||||
end
|
||||
end
|
||||
})
|
||||
--register_chatcommand_alias('wpimp', 'wp_import', 'waypoint_import')
|
||||
|
||||
-- Import waypoints
|
||||
function autofly.import(s)
|
||||
if type(s) ~= 'table' then
|
||||
local ver = s:sub(1, 1)
|
||||
if ver ~= 'M' and ver ~= 'J' then return end
|
||||
s = minetest.decode_base64(s:sub(2))
|
||||
local success, msg = pcall(minetest.decompress, s)
|
||||
if not success then return end
|
||||
if ver == 'M' then
|
||||
s = minetest.deserialize(msg, true)
|
||||
else
|
||||
s = minetest.parse_json(msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Iterate over waypoints to preserve existing ones and check for errors.
|
||||
if type(s) == 'table' then
|
||||
for name, pos in pairs(s) do
|
||||
if type(name) == 'string' and type(pos) == 'string' and
|
||||
name:sub(1, 7) == 'marker-' and minetest.string_to_pos(pos) and
|
||||
storage:get_string(name) ~= pos then
|
||||
-- Prevent collisions
|
||||
local c = 0
|
||||
while #storage:get_string(name) > 0 and c < 50 do
|
||||
name = name .. '_'
|
||||
c = c + 1
|
||||
end
|
||||
|
||||
-- Sanity check
|
||||
if c < 50 then
|
||||
storage:set_string(name, pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,187 @@
|
|||
---
|
||||
-- autominer
|
||||
|
||||
|
||||
autominer = {}
|
||||
local dmg=false
|
||||
local digging=false
|
||||
local radius=6
|
||||
|
||||
local nodes=nlist.get("autominer")
|
||||
|
||||
|
||||
local function sleep(n) -- seconds
|
||||
local t0 = os.clock()
|
||||
while os.clock() - t0 <= n do end
|
||||
end
|
||||
local function shuffle(tbl)
|
||||
for i = #tbl, 2, -1 do
|
||||
local j = math.random(i)
|
||||
tbl[i], tbl[j] = tbl[j], tbl[i]
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
local function checklava(pos)
|
||||
local n=minetest.find_node_near(pos, 2, {'mcl_core:lava_source','mcl_core:lava_flowing'}, true)
|
||||
if n == nil then return false end
|
||||
return true
|
||||
end
|
||||
local function checkgravel(pos)
|
||||
local n=minetest.find_node_near(pos, 1, {'mcl_core:gravel','mcl_core:sand'}, true)
|
||||
if n == nil then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
-- shamelessly stolen from dragonfire autotool
|
||||
local function check_tool(stack, node_groups, old_best_time)
|
||||
local toolcaps = stack:get_tool_capabilities()
|
||||
if not toolcaps then return end
|
||||
local best_time = old_best_time
|
||||
for group, groupdef in pairs(toolcaps.groupcaps) do
|
||||
local level = node_groups[group]
|
||||
if level then
|
||||
local this_time = groupdef.times[level]
|
||||
if this_time < best_time then
|
||||
best_time = this_time
|
||||
end
|
||||
end
|
||||
end
|
||||
return best_time < old_best_time, best_time
|
||||
end
|
||||
|
||||
local function amautotool(pos)
|
||||
local player = minetest.localplayer
|
||||
local inventory = minetest.get_inventory("current_player")
|
||||
local node=minetest.get_node_or_nil(pos)
|
||||
local node_groups = minetest.get_node_def(node.name).groups
|
||||
local new_index = player:get_wield_index()
|
||||
local is_better, best_time = false, math.huge
|
||||
is_better, best_time = check_tool(player:get_wielded_item(), node_groups, best_time)
|
||||
is_better, best_time = check_tool(inventory.hand[1], node_groups, best_time)
|
||||
for index, stack in pairs(inventory.main) do
|
||||
is_better, best_time = check_tool(stack, node_groups, best_time)
|
||||
if is_better then
|
||||
new_index = index
|
||||
end
|
||||
end
|
||||
player:set_wield_index(new_index)
|
||||
end
|
||||
|
||||
local function find_tnod()
|
||||
local pos = minetest.localplayer:get_pos()
|
||||
local rr = vector.add(pos,{x=0,y=0,z=radius})
|
||||
local pos1 = vector.add(pos,{x=radius,y=radius,z=radius})
|
||||
local pos2 = vector.add(pos,{x=-radius,y=-radius,z=-radius})
|
||||
local rt=shuffle(minetest.find_nodes_in_area(pos1, pos2, shuffle(nodes), true))
|
||||
for k,v in pairs(rt) do
|
||||
for kk,vv in pairs(shuffle(v)) do
|
||||
-- minetest.display_chat_message("Found nodes:" ..dump(rt))
|
||||
if ( vv.y > -57 ) and not checkgravel(vv) and not checklava(vv) then
|
||||
rr=vv
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if (checkgravel(rr) or checklava(rr)) then return minetest.after(0.2,find_tnod) end
|
||||
return rr
|
||||
-- return rt
|
||||
end
|
||||
local function get_hnode()
|
||||
local ppos=minetest.localplayer:get_pos()
|
||||
local n=minetest.get_node_or_nil(vector.add(ppos,{x=0,y=1,z=0}))
|
||||
return n
|
||||
end
|
||||
local function dighead()
|
||||
if not minetest.localplayer then return end
|
||||
local ppos=vector.add(minetest.localplayer:get_pos(),{x=0,y=1,z=0})
|
||||
local n=get_hnode()
|
||||
if n==nil or n['name'] == 'air' then return end
|
||||
--amautotool(ppos)
|
||||
minetest.localplayer:set_wield_index(1)
|
||||
minetest.dig_node(ppos)
|
||||
minetest.dig_node(vector.add(ppos,{x=0,y=1,z=0}))
|
||||
digging=false
|
||||
if (minetest.settings:get_bool('aminer_active')) then
|
||||
local hp=minetest.localplayer:get_hp()
|
||||
local hn=get_hnode()
|
||||
if (hp > 17) then
|
||||
minetest.after(0.2,autominer.aminer )
|
||||
else
|
||||
minetest.display_chat_message("taken too much damage. wait.")
|
||||
local ppos=vector.add(minetest.localplayer:get_pos(),{x=0,y=1,z=0})
|
||||
minetest.dig_node(ppos)
|
||||
minetest.dig_node(vector.add(ppos,{x=0,y=1,z=0}))
|
||||
minetest.after(1.0,function() minetest.dig_node(vector.add(ppos,{x=0,y=0,z=0})) end )
|
||||
minetest.after(1.4,function() minetest.dig_node(vector.add(ppos,{x=0,y=1,z=0})) end )
|
||||
minetest.after(1.8,function() minetest.dig_node(vector.add(ppos,{x=0,y=0,z=0})) end )
|
||||
minetest.after(2.5,function() minetest.dig_node(vector.add(ppos,{x=0,y=1,z=0})) end )
|
||||
-- minetest.settings:set_bool("aminer_active",false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function rwarp()
|
||||
if not (minetest.settings:get_bool("aminer_active")) then return end
|
||||
digging=true
|
||||
local nod=find_tnod()
|
||||
if not nod then
|
||||
minetest.display_chat_message('lava detected. stop.')
|
||||
return
|
||||
end
|
||||
minetest.localplayer:set_pos(vector.add(nod,{x=0.3,y=-1.2,z=0.3}))
|
||||
dighead()
|
||||
minetest.after(0.2, dighead)
|
||||
end
|
||||
|
||||
local function amine()
|
||||
minetest.after(1.0,rwarp)
|
||||
end
|
||||
function autominer.aminer()
|
||||
if not digging then
|
||||
digging=true
|
||||
dmg=hpchange.get_status()
|
||||
if dmg then
|
||||
minetest.after(3.0,rwarp)
|
||||
else
|
||||
minetest.after(0.5,rwarp)
|
||||
end
|
||||
end
|
||||
end
|
||||
local lastch=0
|
||||
minetest.register_globalstep(function()
|
||||
if os.time() < lastch + 5 then return end
|
||||
lastch=os.time()
|
||||
if ( minetest.settings:get_bool('aminer_active') ) then
|
||||
dmg=true
|
||||
digging=false
|
||||
autominer.aminer()
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("aminer", {
|
||||
description = "",
|
||||
func = function()
|
||||
dmg=true
|
||||
digging=false
|
||||
minetest.settings:set_bool("aminer_active",true)
|
||||
autominer.aminer()
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("amine", {
|
||||
description = "",
|
||||
func = amine
|
||||
})
|
||||
minetest.register_chatcommand("dhe", {
|
||||
description = "",
|
||||
func = dighead
|
||||
})
|
||||
minetest.register_on_damage_taken(function(hp)
|
||||
dmg=true
|
||||
end)
|
||||
|
||||
|
||||
if (_G["minetest"]["register_cheat"] ~= nil) then
|
||||
minetest.register_cheat("Autominer (!!! ALPHA!! this will lead to you dying!!!)", "Player", "aminer_active")
|
||||
else
|
||||
minetest.settings:set_bool('aminer_active',true)
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = autominer
|
||||
author = cora
|
||||
description = Mining bot
|
|
@ -0,0 +1 @@
|
|||
aminer_active (Enable Autominer) bool false
|
|
@ -0,0 +1,7 @@
|
|||
minetest.register_chatcommand('mtq', {
|
||||
description = 'automt-quit',
|
||||
func = function(param)
|
||||
minetest.log("AUTOMT Actually Quit")
|
||||
minetest.disconnect()
|
||||
end
|
||||
})
|
|
@ -0,0 +1,232 @@
|
|||
-- CC0/Unlicense Emilia 2020
|
||||
|
||||
-- TODO: API
|
||||
-- TODO: all count should be changed to support using a bookbot as a rolling writer
|
||||
-- an alternate solution is to just have an inventory manager bot that intermittently swaps the inventory and activates bookbot
|
||||
-- TODO: local formspec stuff
|
||||
|
||||
--[[
|
||||
COMMANDS
|
||||
|
||||
write <book> <times> Writes the book named <book>, <times> times
|
||||
randwrite <times> Writes randomized books
|
||||
bookadd_form Opens a book formspec for adding a book to the library
|
||||
bookadd_this <shortname> Adds the currently selected book to the library
|
||||
bookdel <shortname> Removes a book from the library
|
||||
bookpeek <book> Peeks at a book in the library
|
||||
booklist Lists all books
|
||||
--]]
|
||||
|
||||
bookbot = {}
|
||||
|
||||
local book_length_max = 4500
|
||||
|
||||
local write = 0
|
||||
local books = {
|
||||
example = {
|
||||
title = "Autobook",
|
||||
author = "Emilia",
|
||||
text = "This is an automatically written book."
|
||||
}
|
||||
}
|
||||
|
||||
local book
|
||||
local book_iterator
|
||||
|
||||
local read_form = [[
|
||||
size[9,8]
|
||||
label[0,0;N]
|
||||
label[0,1;A]
|
||||
textlist[0,2;9,5;;T]
|
||||
]]
|
||||
|
||||
local edit_form = [[
|
||||
size[9,8]
|
||||
field[0,0;9,1;title;;N]
|
||||
field[0,1;9,1;author;;A]
|
||||
textarea[0,2;9,5;text;;T]
|
||||
]]
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
|
||||
local function storage_save()
|
||||
storage:set_string("books", minetest.write_json(books))
|
||||
end
|
||||
|
||||
local function storage_load()
|
||||
local sbooks = storage:get("books")
|
||||
if sbooks then
|
||||
books = minetest.parse_json(sbooks)
|
||||
end
|
||||
end
|
||||
|
||||
storage_load()
|
||||
|
||||
local function open_book()
|
||||
if minetest.switch_to_item("mcl_books:writable_book") then
|
||||
minetest.interact("place")
|
||||
book = book_iterator()
|
||||
else
|
||||
write = 0
|
||||
book = nil
|
||||
book_iterator = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function count_books()
|
||||
local lpmain = minetest.get_inventory("current_player").main
|
||||
local count = 0
|
||||
|
||||
for i, v in ipairs(lpmain) do
|
||||
if v:get_name() == "mcl_books:writable_book" then
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
minetest.register_on_receiving_inventory_form(function(formname, formspec)
|
||||
if formname == "mcl_books:writable_book" and write ~= 0 then
|
||||
minetest.send_inventory_fields("mcl_books:writable_book", {
|
||||
text = book.text,
|
||||
sign = "true",
|
||||
})
|
||||
minetest.close_formspec("")
|
||||
elseif formname == "mcl_books:signing" and write ~= 0 then
|
||||
minetest.send_inventory_fields("mcl_books:signing", {
|
||||
title = book.title,
|
||||
sign = "true"
|
||||
})
|
||||
minetest.close_formspec("")
|
||||
|
||||
write = write - 1
|
||||
if write > 0 then
|
||||
-- this should take lag into consideration
|
||||
minetest.after(0.5, open_book)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local function timesparse(times)
|
||||
local count = 1
|
||||
|
||||
if times then
|
||||
if times == "all" then
|
||||
count = count_books()
|
||||
elseif type(times) == "number" or times:match("^[0-9]+$") then
|
||||
count = tonumber(times)
|
||||
end
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
function bookbot.write_iterator(iterator, write_no)
|
||||
book_iterator = iterator
|
||||
|
||||
write = timesparse(write_no)
|
||||
|
||||
open_book()
|
||||
end
|
||||
|
||||
function bookbot.write_simple(book, write_no)
|
||||
local book_iterator = function()
|
||||
return book
|
||||
end
|
||||
|
||||
bookbot.write_iterator(book_iterator, write_no)
|
||||
end
|
||||
|
||||
function bookbot.write(bookname, write_no)
|
||||
local book = "example"
|
||||
if bookname and books[bookname] then
|
||||
book = books[bookname]
|
||||
end
|
||||
|
||||
bookbot.write_simple(book, write_no)
|
||||
end
|
||||
|
||||
function bookbot.add(bookname, title, author, text)
|
||||
books[bookname] = {
|
||||
title = title,
|
||||
author = author,
|
||||
text = text
|
||||
}
|
||||
|
||||
storage_save()
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("write", {
|
||||
description = "Write a book.",
|
||||
params = "<book> <?ntimes/all>",
|
||||
func = function(params)
|
||||
local p = string.split(params, " ")
|
||||
|
||||
if #p == 0 then
|
||||
minetest.display_chat_message("Error: book short name required")
|
||||
return
|
||||
end
|
||||
|
||||
bookbot.write(p[1], p[2])
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("bookadd_this", {
|
||||
description = "Add the currently wielded book to the library, <name> is for the name in the library.",
|
||||
params = "<name>",
|
||||
func = function(params)
|
||||
if params == "" then
|
||||
minetest.display_chat_message("Error: no short name given")
|
||||
return
|
||||
end
|
||||
|
||||
local wielded = minetest.localplayer:get_wielded_item()
|
||||
if wielded:get_name() == "mcl_books:written_book" then
|
||||
local meta = wielded:get_meta():to_table()
|
||||
bookbot.add(params,
|
||||
meta.fields.title,
|
||||
meta.fields.author,
|
||||
meta.fields.text)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("booklist", {
|
||||
description = "List all saved books.",
|
||||
func = function()
|
||||
local out = ""
|
||||
local first = true
|
||||
for k, v in pairs(books) do
|
||||
if not first then
|
||||
out = out .. ", "
|
||||
end
|
||||
out = out .. k
|
||||
first = false
|
||||
end
|
||||
minetest.display_chat_message("Saved books:")
|
||||
minetest.display_chat_message(out)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("randwrite", {
|
||||
description = "Write random books.",
|
||||
params = "<?times/all>",
|
||||
func = function(params)
|
||||
local p = string.split(params, " ")
|
||||
|
||||
book_iterator = function()
|
||||
local out = {}
|
||||
for i = 1, book_length_max do
|
||||
table.insert(out, string.char(math.random(0x20, 0xFF)))
|
||||
end
|
||||
return {
|
||||
title = "Random book",
|
||||
author = "The computer",
|
||||
text = table.concat(out)
|
||||
}
|
||||
end
|
||||
|
||||
bookbot.write_iterator(book_iterator, p[1])
|
||||
end
|
||||
})
|
|
@ -0,0 +1,113 @@
|
|||
--
|
||||
-- coras Chat hacks
|
||||
-- * verify death messages
|
||||
-- * log chat to stdout
|
||||
|
||||
cchat = {}
|
||||
|
||||
-- verify death
|
||||
table.insert(minetest.registered_on_receiving_chat_message, 1, function(msg)
|
||||
local d = msg:find('\1b@mcl_death_messages\1b') --mineclone specific
|
||||
if d then
|
||||
-- minetest.send_chat_message("real.") --uncomment to publish approval
|
||||
minetest.display_chat_message("real.")
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
|
||||
-- chat logging
|
||||
local mod_name = minetest.get_current_modname()
|
||||
|
||||
local function log(level, message)
|
||||
minetest.log(level, ('[%s] %s'):format(mod_name, message))
|
||||
end
|
||||
|
||||
log('action', 'Chatlog loading...')
|
||||
|
||||
local LOG_LEVEL = 'action'
|
||||
|
||||
local server_info = minetest.get_server_info()
|
||||
local server_id = server_info.address .. ':' .. server_info.port
|
||||
local my_name = ''
|
||||
|
||||
local register_on_send = minetest.register_on_sending_chat_message or minetest.register_on_sending_chat_messages
|
||||
local register_on_receive = minetest.register_on_receiving_chat_message or minetest.register_on_receiving_chat_messages
|
||||
|
||||
|
||||
local function safe(func)
|
||||
-- wrap a function w/ logic to avoid crashing the game
|
||||
local f = function(...)
|
||||
local status, out = pcall(func, ...)
|
||||
if status then
|
||||
return out
|
||||
else
|
||||
log('warning', 'Error (func): ' .. out)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
local set_my_name_tries = 0
|
||||
local function set_my_name()
|
||||
if minetest.localplayer then
|
||||
my_name = minetest.localplayer:get_name()
|
||||
elseif set_my_name_tries < 20 then
|
||||
set_my_name_tries = set_my_name_tries + 1
|
||||
minetest.after(1, set_my_name)
|
||||
else
|
||||
my_name = ''
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function loglastlogs()
|
||||
if not fren then return end
|
||||
for k,v in pairs(fren.friends) do
|
||||
if fren.on_server(fren.name_of(k)) then
|
||||
log("LASTLOGLOG START")
|
||||
--minetest.display_chat_message('Last login of friend ' .. fren.name_of(k))
|
||||
log("Last login of friend "..fren.name_of(k))
|
||||
minetest.send_chat_message("/last-login "..fren.name_of(k))
|
||||
end
|
||||
end
|
||||
for k,v in pairs(fren.enemies) do
|
||||
if fren.on_server(fren.name_of(k)) then
|
||||
log("Last login of enemy "..fren.name_of(k))
|
||||
--minetest.display_chat_message('Last login of friend ' .. fren.name_of(k))
|
||||
minetest.send_chat_message("/last-login "..fren.name_of(k))
|
||||
minetest.after("5.0",function() log("LASTLOGLOG END") end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--minetest.after("5.0",function() loglastlogs() end)
|
||||
|
||||
if minetest.register_on_connect then
|
||||
minetest.register_on_connect(set_my_name)
|
||||
elseif minetest.register_on_mods_loaded then
|
||||
minetest.register_on_mods_loaded(set_my_name)
|
||||
else
|
||||
minetest.after(1, set_my_name)
|
||||
end
|
||||
|
||||
|
||||
if register_on_send then
|
||||
register_on_send(safe(function(message)
|
||||
local msg = minetest.strip_colors(message)
|
||||
if msg ~= '' then
|
||||
log(LOG_LEVEL, ('%s@%s [sent] %s'):format(my_name, server_id, msg))
|
||||
end
|
||||
end))
|
||||
end
|
||||
|
||||
if register_on_receive then
|
||||
register_on_receive(safe(function(message)
|
||||
local msg = minetest.strip_colors(message)
|
||||
if msg ~= '' then
|
||||
log(LOG_LEVEL, ('%s@%s %s'):format(my_name, server_id, msg))
|
||||
end
|
||||
end))
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = cchat
|
||||
author = cora
|
||||
description = cora's chat extensions, primarily log to stdout
|
|
@ -0,0 +1,91 @@
|
|||
if INIT == "client" then
|
||||
|
||||
core.register_chatcommand("say", {
|
||||
description = "Send raw text",
|
||||
func = function(text)
|
||||
minetest.send_chat_message(text)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("teleport", {
|
||||
params = "<X>,<Y>,<Z>",
|
||||
description = "Teleport to relative coordinates.",
|
||||
func = function(param)
|
||||
local success, pos = minetest.parse_relative_pos(param)
|
||||
if success then
|
||||
minetest.localplayer:set_pos(pos)
|
||||
return true, "Teleporting to " .. minetest.pos_to_string(pos)
|
||||
end
|
||||
return false, pos
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("wielded", {
|
||||
description = "Print itemstring of wieleded item",
|
||||
func = function()
|
||||
return true, minetest.localplayer:get_wielded_item():get_name()
|
||||
end
|
||||
})
|
||||
|
||||
core.register_chatcommand("disconnect", {
|
||||
description = "Exit to main menu",
|
||||
func = function(param)
|
||||
minetest.disconnect()
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("players", {
|
||||
description = "List online players",
|
||||
func = function(param)
|
||||
return true, "Online players: " .. table.concat(minetest.get_player_names(), ", ")
|
||||
end
|
||||
})
|
||||
|
||||
core.register_chatcommand("kill", {
|
||||
description = "Kill yourself",
|
||||
func = function()
|
||||
minetest.send_damage(minetest.localplayer:get_hp())
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("hop", {
|
||||
description = "Hop",
|
||||
func = function()
|
||||
minetest.set_keypress("jump", true)
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("set", {
|
||||
params = "([-n] <name> <value>) | <name>",
|
||||
description = "Set or read client configuration setting",
|
||||
func = function(param)
|
||||
local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
|
||||
if arg and arg == "-n" and setname and setvalue then
|
||||
minetest.settings:set(setname, setvalue)
|
||||
return true, setname .. " = " .. setvalue
|
||||
end
|
||||
|
||||
setname, setvalue = string.match(param, "([^ ]+) (.+)")
|
||||
if setname and setvalue then
|
||||
if not minetest.settings:get(setname) then
|
||||
return false, "Failed. Use '.set -n <name> <value>' to create a new setting."
|
||||
end
|
||||
minetest.settings:set(setname, setvalue)
|
||||
return true, setname .. " = " .. setvalue
|
||||
end
|
||||
|
||||
setname = string.match(param, "([^ ]+)")
|
||||
if setname then
|
||||
setvalue = minetest.settings:get(setname)
|
||||
if not setvalue then
|
||||
setvalue = "<not set>"
|
||||
end
|
||||
return true, setname .. " = " .. setvalue
|
||||
end
|
||||
|
||||
return false, "Invalid parameters (see .help set)."
|
||||
end,
|
||||
})
|
||||
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = commands
|
||||
author = Fleckenstein
|
||||
description = Misc cheat commands
|
|
@ -0,0 +1,48 @@
|
|||
minetest.register_on_receiving_chat_message(function(message)
|
||||
if message:sub(1, 1) == "#" and minetest.settings:get_bool("ignore_status_messages") ~= false then
|
||||
return true
|
||||
elseif message:find('\1b@mcl_death_messages\1b') and minetest.settings:get_bool("mark_deathmessages") ~= false then
|
||||
minetest.display_chat_message(minetest.colorize("#F25819", "[Deathmessage] ") .. message)
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
function minetest.send_colorized(message)
|
||||
local starts_with = message:sub(1, 1)
|
||||
|
||||
if starts_with == "/" or starts_with == "." then return end
|
||||
|
||||
local reverse = minetest.settings:get_bool("chat_reverse")
|
||||
|
||||
if reverse then
|
||||
local msg = ""
|
||||
for i = 1, #message do
|
||||
msg = message:sub(i, i) .. msg
|
||||
end
|
||||
message = msg
|
||||
end
|
||||
|
||||
local use_chat_color = minetest.settings:get_bool("use_chat_color")
|
||||
local color = minetest.settings:get("chat_color")
|
||||
|
||||
if use_chat_color and color then
|
||||
local msg
|
||||
if color == "rainbow" then
|
||||
msg = minetest.rainbow(message)
|
||||
else
|
||||
msg = minetest.colorize(color, message)
|
||||
end
|
||||
message = msg
|
||||
end
|
||||
|
||||
minetest.send_chat_message(message)
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_on_sending_chat_message(minetest.send_colorized)
|
||||
|
||||
|
||||
minetest.register_cheat("IgnoreStatus", "Chat", "ignore_status_messages")
|
||||
minetest.register_cheat("DeathMessages", "Chat", "mark_deathmessages")
|
||||
minetest.register_cheat("ColoredChat", "Chat", "use_chat_color")
|
||||
minetest.register_cheat("ReversedChat", "Chat", "chat_reverse")
|
|
@ -0,0 +1,3 @@
|
|||
name = chat
|
||||
author = Fleckenstein
|
||||
description = The chat modifications of Dragonfireclient
|
|
@ -0,0 +1,3 @@
|
|||
chat_color (Chat Color) string white
|
||||
chat_reverse (Reverse Chat messages) bool false
|
||||
ignore_status_messages (Ignore status messages from server) bool false
|
|
@ -0,0 +1,193 @@
|
|||
local placed_crystal
|
||||
local switched_to_totem = 0
|
||||
local used_sneak = true
|
||||
local totem_move_action = InventoryAction("move")
|
||||
totem_move_action:to("current_player", "main", 9)
|
||||
|
||||
local mobs_friends = {
|
||||
'mobs_mc_bat.png',
|
||||
'mobs_mc_cat_black.png',
|
||||
'mobs_mc_cat_ocelot.png',
|
||||
'mobs_mc_cat_red.png',
|
||||
'mobs_mc_cat_siamese.png',
|
||||
'mobs_mc_diamond_horse_armor.png',
|
||||
'mobs_mc_donkey.png',
|
||||
'mobs_mc_wolf_collar.png',
|
||||
'mobs_mc_wolf.png',
|
||||
'mobs_mc_wolf_tame.png',
|
||||
'mobs_mc_villager_butcher.png',
|
||||
'mobs_mc_villager_farmer.png',
|
||||
'mobs_mc_villager_librarian.png',
|
||||
'mobs_mc_villager.png',
|
||||
'mobs_mc_villager_priest.png',
|
||||
'mobs_mc_villager_smith.png',
|
||||
'mobs_mc_iron_golem.png',
|
||||
'mobs_mc_iron_horse_armor.png',
|
||||
'mobs_mc_mooshroom.png',
|
||||
'mobs_mc_mule.png',
|
||||
'mobs_mc_pig.png',
|
||||
'mobs_mc_pig_saddle.png',
|
||||
'mobs_mc_polarbear.png',
|
||||
'mobs_mc_rabbit_black.png',
|
||||
'mobs_mc_rabbit_brown.png',
|
||||
'mobs_mc_rabbit_caerbannog.png',
|
||||
'mobs_mc_rabbit_gold.png',
|
||||
'mobs_mc_rabbit_salt.png',
|
||||
'mobs_mc_rabbit_toast.png',
|
||||
'mobs_mc_rabbit_white.png',
|
||||
'mobs_mc_rabbit_white_splotched.png',
|
||||
'mobs_mc_sheep_fur.png',
|
||||
'mobs_mc_sheep.png',
|
||||
'mobs_mc_horse_armor_diamond.png',
|
||||
'mobs_mc_horse_armor_gold.png',
|
||||
'mobs_mc_horse_armor_iron.png',
|
||||
'mobs_mc_horse_black.png',
|
||||
'mobs_mc_horse_brown.png',
|
||||
'mobs_mc_horse_chestnut.png',
|
||||
'mobs_mc_horse_darkbrown.png',
|
||||
'mobs_mc_horse_gray.png',
|
||||
'mobs_mc_horse_creamy.png',
|
||||
'mobs_mc_horse_markings_blackdots.png',
|
||||
'mobs_mc_horse_markings_whitedots.png',
|
||||
'mobs_mc_horse_markings_whitefield.png',
|
||||
'mobs_mc_horse_markings_white.png',
|
||||
'mobs_mc_horse_white.png',
|
||||
'mobs_mc_snowman',
|
||||
'mobs_mc_chicken.png',
|
||||
'mobs_mc_enderman.png',
|
||||
'mobs_mc_cow.png'
|
||||
}
|
||||
|
||||
local mobs_bad = {
|
||||
'mcl_totems_totem.png',
|
||||
'mobs_mc_blaze.png',
|
||||
'mobs_mc_cave_spider.png',
|
||||
'mobs_mc_creeper.png',
|
||||
'mobs_mc_dragon.png',
|
||||
'mobs_mc_endergolem.png',
|
||||
'mobs_mc_magmacube.png',
|
||||
'mobs_mc_enderman_eyes.png',
|
||||
'mobs_mc_endermite.png',
|
||||
'mobs_mc_ghast.png',
|
||||
'mobs_mc_gold_horse_armor.png',
|
||||
'mobs_mc_guardian_elder.png',
|
||||
'mobs_mc_guardian.png',
|
||||
'mobs_mc_husk.png',
|
||||
'mobs_mc_shulker_black.png',
|
||||
'mobs_mc_shulker_blue.png',
|
||||
'mobs_mc_shulker_brown.png',
|
||||
'mobs_mc_shulker_cyan.png',
|
||||
'mobs_mc_shulker_gray.png',
|
||||
'mobs_mc_shulker_green.png',
|
||||
'mobs_mc_shulker_light_blue.png',
|
||||
'mobs_mc_shulker_lime.png',
|
||||
'mobs_mc_shulker_magenta.png',
|
||||
'mobs_mc_shulker_orange.png',
|
||||
'mobs_mc_shulker_pink.png',
|
||||
'mobs_mc_shulker_purple.png',
|
||||
'mobs_mc_shulker_red.png',
|
||||
'mobs_mc_shulker_silver.png',
|
||||
'mobs_mc_shulker_white.png',
|
||||
'mobs_mc_shulker_yellow.png',
|
||||
'mobs_mc_silverfish.png',
|
||||
'mobs_mc_skeleton.png',
|
||||
'mobs_mc_slime.png',
|
||||
'mobs_mc_spider_eyes.png',
|
||||
'mobs_mc_spider.png',
|
||||
'mobs_mc_squid.png',
|
||||
'mobs_mc_stray.png',
|
||||
'mobs_mc_stray_overlay.png',
|
||||
'mobs_mc_vex.png',
|
||||
'mobs_mc_vex_charging.png',
|
||||
'mobs_mc_vindicator.png',
|
||||
'mobs_mc_evoker.png',
|
||||
'mobs_mc_illusionist.png',
|
||||
'mobs_mc_witch.png',
|
||||
'mobs_mc_wither.png',
|
||||
'mobs_mc_wither_skeleton.png',
|
||||
'mobs_mc_wolf_angry.png',
|
||||
'mobs_mc_zombie_butcher.png',
|
||||
'mobs_mc_zombie_farmer.png',
|
||||
'mobs_mc_zombie_librarian.png',
|
||||
'mobs_mc_zombie_priest.png',
|
||||
'mobs_mc_zombie_smith.png',
|
||||
'mobs_mc_zombie_villager.png',
|
||||
'mobs_mc_zombie_pigman.png',
|
||||
'mobs_mc_zombie.png',
|
||||
'mobs_mc_horse_zombie.png'
|
||||
}
|
||||
|
||||
--minetest.register_list_command("friend", "Configure Friend List (friends dont get attacked by Killaura or Forcefield)", "friendlist")
|
||||
local nexthit=0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
local player = minetest.localplayer
|
||||
if not player then return end
|
||||
local control = player:get_control()
|
||||
local pointed = minetest.get_pointed_thing()
|
||||
local item = player:get_wielded_item():get_name()
|
||||
if minetest.settings:get_bool("killaura") or minetest.settings:get_bool("forcefield") and control.dig then
|
||||
if nexthit > os.clock() then return end
|
||||
nexthit=os.clock() + 0.01
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(player:get_pos(), 5)) do
|
||||
local do_attack = false
|
||||
local txt=obj:get_item_textures()
|
||||
if(obj:is_player() and fren.is_enemy(obj:get_name())) then do_attack=true end
|
||||
for k,v in pairs(mobs_bad) do if txt:find(v) then do_attack=true end end
|
||||
if do_attack then
|
||||
local owx=core.localplayer:get_wield_index()
|
||||
minetest.switch_to_item('mcl_tools:sword_diamond')
|
||||
obj:punch()
|
||||
core.localplayer:set_wield_index(owx)
|
||||
end
|
||||
end
|
||||
elseif minetest.settings:get_bool("crystal_pvp") then
|
||||
if placed_crystal then
|
||||
if minetest.switch_to_item("mobs_mc:totem") then
|
||||
switched_to_totem = 5
|
||||
end
|
||||
placed_crystal = false
|
||||
elseif switched_to_totem > 0 then
|
||||
if item ~= "mobs_mc:totem" then
|
||||
switched_to_totem = 0
|
||||
elseif pointed and pointed.type == "object" then
|
||||
pointed.ref:punch()
|
||||
switched_to_totem = 0
|
||||
else
|
||||
switched_to_totem = switched_to_totem
|
||||
end
|
||||
elseif control.place and item == "mcl_end:crystal" then
|
||||
placed_crystal = true
|
||||
elseif control.sneak then
|
||||
if pointed and pointed.type == "node" and not used_sneak then
|
||||
local pos = minetest.get_pointed_thing_position(pointed)
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if node and (node.name == "mcl_core:obsidian" or node.name == "mcl_core:bedrock") then
|
||||
minetest.switch_to_item("mcl_end:crystal")
|
||||
minetest.place_node(pos)
|
||||
placed_crystal = true
|
||||
end
|
||||
end
|
||||
used_sneak = true
|
||||
else
|
||||
used_sneak = false
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.settings:get_bool("autototem") then
|
||||
local totem_stack = minetest.get_inventory("current_player").main[9]
|
||||
if totem_stack and totem_stack:get_name() ~= "mobs_mc:totem" then
|
||||
local totem_index = minetest.find_item("mobs_mc:totem")
|
||||
if totem_index then
|
||||
totem_move_action:from("current_player", "main", totem_index)
|
||||
totem_move_action:apply()
|
||||
player:set_wield_index(9)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
minetest.register_cheat("Killaura", "Combat", "killaura")
|
||||
minetest.register_cheat("Forcefield", "Combat", "forcefield")
|
||||
minetest.register_cheat("CrystalPvP", "Combat", "crystal_pvp")
|
||||
minetest.register_cheat("AutoTotem", "Combat", "autototem")
|
|
@ -0,0 +1,179 @@
|
|||
local drop_action = InventoryAction("drop")
|
||||
|
||||
local strip_move_act = InventoryAction("move")
|
||||
strip_move_act:to("current_player", "craft", 1)
|
||||
local strip_craft_act = InventoryAction("craft")
|
||||
strip_craft_act:craft("current_player")
|
||||
local strip_move_back_act = InventoryAction("move")
|
||||
strip_move_back_act:from("current_player", "craftresult", 1)
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
local player = minetest.localplayer
|
||||
if not player then return end
|
||||
local item = player:get_wielded_item()
|
||||
local itemdef = minetest.get_item_def(item:get_name())
|
||||
local wieldindex = player:get_wield_index()
|
||||
-- AutoRefill
|
||||
if minetest.settings:get_bool("autorefill") and itemdef then
|
||||
local space = item:get_free_space()
|
||||
local i = minetest.find_item(item:get_name(), wieldindex + 1)
|
||||
if i and space > 0 then
|
||||
local move_act = InventoryAction("move")
|
||||
move_act:to("current_player", "main", wieldindex)
|
||||
move_act:from("current_player", "main", i)
|
||||
move_act:set_count(space)
|
||||
move_act:apply()
|
||||
end
|
||||
end
|
||||
-- AutoPlanks (Strip in DF)
|
||||
if minetest.settings:get_bool("autoplanks") then
|
||||
if itemdef and itemdef.groups.tree and player:get_control().place then
|
||||
strip_move_act:from("current_player", "main", wieldindex)
|
||||
strip_move_back_act:to("current_player", "main", wieldindex)
|
||||
strip_move_act:apply()
|
||||
strip_craft_act:apply()
|
||||
strip_move_back_act:apply()
|
||||
end
|
||||
end
|
||||
-- AutoEject
|
||||
if minetest.settings:get_bool("autoeject") then
|
||||
local list = (minetest.settings:get("eject_items") or ""):split(",")
|
||||
local inventory = minetest.get_inventory("current_player")
|
||||
for index, stack in pairs(inventory.main) do
|
||||
if table.indexof(list, stack:get_name()) ~= -1 then
|
||||
drop_action:from("current_player", "main", index)
|
||||
drop_action:apply()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_list_command("eject", "Configure AutoEject", "eject_items")
|
||||
|
||||
-- AutoTool
|
||||
|
||||
local function check_tool(stack, node_groups, old_best_time)
|
||||
local toolcaps = stack:get_tool_capabilities()
|
||||
if not toolcaps then return end
|
||||
local best_time = old_best_time
|
||||
for group, groupdef in pairs(toolcaps.groupcaps) do
|
||||
local level = node_groups[group]
|
||||
if level then
|
||||
local this_time = groupdef.times[level]
|
||||
if this_time and this_time < best_time then
|
||||
best_time = this_time
|
||||
end
|
||||
end
|
||||
end
|
||||
return best_time < old_best_time, best_time
|
||||
end
|
||||
|
||||
local function find_best_tool(nodename, switch)
|
||||
local player = minetest.localplayer
|
||||
local inventory = minetest.get_inventory("current_player")
|
||||
local node_groups = minetest.get_node_def(nodename).groups
|
||||
local new_index = player:get_wield_index()
|
||||
local is_better, best_time = false, math.huge
|
||||
|
||||
is_better, best_time = check_tool(player:get_wielded_item(), node_groups, best_time)
|
||||
if inventory.hand then
|
||||
is_better, best_time = check_tool(inventory.hand[1], node_groups, best_time)
|
||||
end
|
||||
|
||||
for index, stack in ipairs(inventory.main) do
|
||||
is_better, best_time = check_tool(stack, node_groups, best_time)
|
||||
if is_better then
|
||||
new_index = index
|
||||
end
|
||||
end
|
||||
|
||||
return new_index
|
||||
end
|
||||
|
||||
function minetest.select_best_tool(nodename)
|
||||
minetest.localplayer:set_wield_index(find_best_tool(nodename))
|
||||
end
|
||||
|
||||
local new_index, old_index, pointed_pos
|
||||
|
||||
minetest.register_on_punchnode(function(pos, node)
|
||||
if minetest.settings:get_bool("autotool") then
|
||||
pointed_pos = pos
|
||||
old_index = old_index or minetest.localplayer:get_wield_index()
|
||||
new_index = find_best_tool(node.name)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
local player = minetest.localplayer
|
||||
if not new_index then return end
|
||||
if minetest.settings:get_bool("autotool") then
|
||||
local pt = minetest.get_pointed_thing()
|
||||
if pt and pt.type == "node" and vector.equals(minetest.get_pointed_thing_position(pt), pointed_pos) and player:get_control().dig then
|
||||
player:set_wield_index(new_index)
|
||||
return
|
||||
end
|
||||
end
|
||||
player:set_wield_index(old_index)
|
||||
new_index, old_index, pointed_pos = nil
|
||||
end)
|
||||
|
||||
-- Enderchest
|
||||
|
||||
function get_itemslot_bg(x, y, w, h)
|
||||
local out = ""
|
||||
for i = 0, w - 1, 1 do
|
||||
for j = 0, h - 1, 1 do
|
||||
out = out .."image["..x+i..","..y+j..";1,1;mcl_formspec_itemslot.png]"
|
||||
end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
local enderchest_formspec = "size[9,8.75]"..
|
||||
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", "Ender Chest")).."]"..
|
||||
"list[current_player;enderchest;0,0.5;9,3;]"..
|
||||
get_itemslot_bg(0,0.5,9,3)..
|
||||
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", "Inventory")).."]"..
|
||||
"list[current_player;main;0,4.5;9,3;9]"..
|
||||
get_itemslot_bg(0,4.5,9,3)..
|
||||
"list[current_player;main;0,7.74;9,1;]"..
|
||||
get_itemslot_bg(0,7.74,9,1)..
|
||||
"listring[current_player;enderchest]"..
|
||||
"listring[current_player;main]"
|
||||
|
||||
function minetest.open_enderchest()
|
||||
minetest.show_formspec("inventory:enderchest", enderchest_formspec)
|
||||
end
|
||||
|
||||
-- HandSlot
|
||||
|
||||
local hand_formspec = "size[9,8.75]"..
|
||||
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", "Hand")).."]"..
|
||||
"list[current_player;hand;0,0.5;1,1;]"..
|
||||
get_itemslot_bg(0,0.5,1,1)..
|
||||
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", "Inventory")).."]"..
|
||||
"list[current_player;main;0,4.5;9,3;9]"..
|
||||
get_itemslot_bg(0,4.5,9,3)..
|
||||
"list[current_player;main;0,7.74;9,1;]"..
|
||||
get_itemslot_bg(0,7.74,9,1)..
|
||||
"listring[current_player;hand]"..
|
||||
"listring[current_player;main]"
|
||||
|
||||
function minetest.open_handslot()
|
||||
minetest.show_formspec("inventory:hand", hand_formspec)
|
||||
end
|
||||
|
||||
minetest.register_cheat("AutoEject", "Inventory", "autoeject")
|
||||
minetest.register_cheat("AutoTool", "Inventory", "autotool")
|
||||
minetest.register_cheat("Hand", "Inventory", minetest.open_handslot)
|
||||
minetest.register_cheat("Enderchest", "Inventory", minetest.open_enderchest)
|
||||
minetest.register_cheat("AutoPlanks", "Inventory", "autoplanks")
|
||||
minetest.register_cheat("AutoRefill", "Inventory", "autorefill")
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
dofile(modpath .. "/next_item.lua")
|
||||
dofile(modpath .. "/invhack.lua")
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
minetest.register_chatcommand("invhack", {
|
||||
func = function(player)
|
||||
minetest.show_formspec(
|
||||
"invhack:invhack",
|
||||
""
|
||||
.. "size[8,7.5]"
|
||||
.. "list[player:" .. player .. ";main;0,3.5;8,4;]"
|
||||
.. "list[player:" .. player .. ";craft;3,0;3,3;]"
|
||||
.. "list[player:" .. player .. ";craftpreview;7,1;1,1;]"
|
||||
)
|
||||
end
|
||||
})
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
name = inventory
|
||||
author = Fleckenstein
|
||||
description = The inventory cheats for Dragonfireclient
|
||||
dependencies = list
|
|
@ -0,0 +1,18 @@
|
|||
local elapsed_time = 0
|
||||
local tick_time = 0.05
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
elapsed_time = elapsed_time + dtime
|
||||
if elapsed_time < tick_time then return end
|
||||
local player = minetest.localplayer
|
||||
if not player then return end
|
||||
local item = player:get_wielded_item()
|
||||
if item:get_count() == 0 and minetest.settings:get_bool("next_item") then
|
||||
local index = player:get_wield_index()
|
||||
player:set_wield_index(index + 1)
|
||||
end
|
||||
elapsed_time = 0
|
||||
end)
|
||||
|
||||
minetest.register_cheat("NextItem", "Inventory", "next_item")
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
next_item (NextItem) bool false
|
||||
autotool (AutoTool) bool false
|
||||
autoeject (AutoEject) bool false
|
||||
eject_items (AutoEject Items) string
|
|
@ -0,0 +1,47 @@
|
|||
list = {}
|
||||
|
||||
function list.new(desc, setting)
|
||||
local def = {}
|
||||
def.description = desc
|
||||
def.params = "del <item> | add <item> | list"
|
||||
function def.func(param)
|
||||
local list = (minetest.settings:get(setting) or ""):split(",")
|
||||
if param == "list" then
|
||||
return true, table.concat(list, ", ")
|
||||
else
|
||||
local sparam = param:split(" ")
|
||||
local cmd = sparam[1]
|
||||
local item = sparam[2]
|
||||
if cmd == "del" then
|
||||
if not item then
|
||||
return false, "Missing item."
|
||||
end
|
||||
local i = table.indexof(list, item)
|
||||
if i == -1 then
|
||||
return false, item .. " is not on the list."
|
||||
else
|
||||
table.remove(list, i)
|
||||
minetest.settings:set(setting, table.concat(list, ","))
|
||||
return true, "Removed " .. item .. " from the list."
|
||||
end
|
||||
elseif cmd == "add" then
|
||||
if not item then
|
||||
return false, "Missing item."
|
||||
end
|
||||
local i = table.indexof(list, item)
|
||||
if i ~= -1 then
|
||||
return false, item .. " is already on the list."
|
||||
else
|
||||
table.insert(list, item)
|
||||
minetest.settings:set(setting, table.concat(list, ","))
|
||||
return true, "Added " .. item .. " to the list."
|
||||
end
|
||||
end
|
||||
end
|
||||
return false, "Invalid usage. (See /help <command>)"
|
||||
end
|
||||
return def
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("xray", list.new("Configure X-Ray", "xray_nodes"))
|
||||
--minetest.register_chatcommand("Configure Search Nodes", "search_nodes")
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
local function register_keypress_cheat(cheat, keyname, condition)
|
||||
local was_active = false
|
||||
minetest.register_globalstep(function()
|
||||
local is_active = minetest.settings:get_bool(cheat) and (not condition or condition())
|
||||
if is_active then
|
||||
minetest.set_keypress(keyname, true)
|
||||
elseif was_active then
|
||||
minetest.set_keypress(keyname, false)
|
||||
end
|
||||
was_active = is_active
|
||||
end)
|
||||
end
|
||||
|
||||
register_keypress_cheat("autosneak", "sneak", function()
|
||||
return minetest.localplayer:is_touching_ground()
|
||||
end)
|
||||
register_keypress_cheat("autosprint", "special1")
|
||||
|
||||
local legit_override
|
||||
|
||||
local function get_override_factor(name)
|
||||
if minetest.settings:get_bool("override_" .. name) then
|
||||
return tonumber(minetest.settings:get("override_" .. name .. "_factor")) or 1
|
||||
else
|
||||
return 1.0
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if not legit_override then return end
|
||||
local override = table.copy(legit_override)
|
||||
override.speed = override.speed * get_override_factor("speed")
|
||||
override.jump = override.jump * get_override_factor("jump")
|
||||
override.gravity = override.gravity * get_override_factor("gravity")
|
||||
minetest.localplayer:set_physics_override(override)
|
||||
end)
|
||||
|
||||
minetest.register_on_recieve_physics_override(function(override)
|
||||
legit_override = override
|
||||
return true
|
||||
end)
|
||||
|
||||
minetest.register_cheat("AutoSneak", "Movement", "autosneak")
|
||||
minetest.register_cheat("AutoSprint", "Movement", "autosprint")
|
|
@ -0,0 +1,3 @@
|
|||
name = autosneak
|
||||
desciption = Adds the AutoSneak feature to dragonfire.
|
||||
author = Fleckenstein
|
|
@ -0,0 +1 @@
|
|||
autosneak (AutoSneak) bool false
|
|
@ -0,0 +1,109 @@
|
|||
local positions, index, global_goal
|
||||
|
||||
local function roundvec(v, d)
|
||||
return vector.divide(vector.round(vector.multiply(v, d)), d)
|
||||
end
|
||||
|
||||
local function findpath(pos)
|
||||
global_goal = pos
|
||||
index = 2
|
||||
positions = minetest.find_path(
|
||||
minetest.localplayer:get_pos(),
|
||||
pos,
|
||||
tonumber(minetest.settings:get("goto_max_distance") or 25),
|
||||
tonumber(minetest.settings:get("goto_max_jump") or 1),
|
||||
tonumber(minetest.settings:get("goto_max_drop") or minetest.settings:get_bool("prevent_natural_damage") and 1000 or 5)
|
||||
)
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("goto", {
|
||||
description = "Go to a position (use pathfinding).",
|
||||
param = "<pos>",
|
||||
func = function(param)
|
||||
if positions then
|
||||
return false, "Goto is still active. Use .gotoabort to abort it."
|
||||
end
|
||||
local success, pos = minetest.parse_pos(param)
|
||||
if not success then
|
||||
return false, pos
|
||||
end
|
||||
findpath(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("gotoabort", {
|
||||
description = "Abort goto.",
|
||||
param = "<pos>",
|
||||
func = function(param)
|
||||
if not positions then
|
||||
return false, "Goto is currently not running (and also not walking haha)"
|
||||
end
|
||||
minetest.set_keypress("forward", false)
|
||||
minetest.set_keypress("sneak", false)
|
||||
positions, index, global_goal = nil
|
||||
return true, "Aborted."
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if positions then
|
||||
minetest.set_keypress("forward", true)
|
||||
minetest.set_keypress("sneak", false)
|
||||
local player = minetest.localplayer
|
||||
local pos = player:get_pos()
|
||||
local goal, next_goal = positions[index], positions[index+1]
|
||||
if not goal then
|
||||
positions, index, global_goal = nil
|
||||
minetest.set_keypress("forward", false)
|
||||
minetest.display_chat_message("Reached goal.")
|
||||
return
|
||||
end
|
||||
if next_goal then
|
||||
local d, dn = vector.subtract(pos, goal), vector.subtract(next_goal, goal)
|
||||
for k, v in pairs(dn) do
|
||||
if v ~= 0 and k ~= "y" then
|
||||
local cv = d[k]
|
||||
if v > 0 and cv > 0 or v < 0 and cv < 0 then
|
||||
index = index + 1
|
||||
goal = next_goal
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local npos = vector.add(goal, {x = 0, y = 1, z = 0})
|
||||
local node = minetest.get_node_or_nil(npos)
|
||||
if node and node.name ~= air then
|
||||
minetest.dig_node(npos)
|
||||
end
|
||||
local velocity = player:get_velocity()
|
||||
velocity.y = 0
|
||||
if vector.length(velocity) < 0.1 then
|
||||
findpath(global_goal)
|
||||
return
|
||||
end
|
||||
local distance = vector.distance(pos, goal)
|
||||
if not next_goal and distance < 1 then
|
||||
index = index + 1
|
||||
end
|
||||
local direction = vector.direction(pos, vector.new(goal.x, 0, goal.z))
|
||||
local yaw = player:get_yaw() % 360
|
||||
local goal_yaw = math.deg(math.atan2(-direction.x, direction.z)) % 360
|
||||
local diff = math.abs(goal_yaw - yaw)
|
||||
if diff > 175 and diff < 185 and distance < 1 then
|
||||
index = index + 1
|
||||
elseif diff > 10 and diff < 350 then
|
||||
if yaw < goal_yaw and diff < 180 or yaw > goal_yaw and diff > 180 then
|
||||
yaw = yaw + 10
|
||||
elseif yaw < goal_yaw and diff > 180 or yaw > goal_yaw and diff < 180 then
|
||||
yaw = yaw - 10
|
||||
end
|
||||
if diff >= 90 and diff <= 270 then
|
||||
minetest.set_keypress("sneak", true)
|
||||
end
|
||||
player:set_yaw(yaw)
|
||||
else
|
||||
player:set_yaw(goal_yaw)
|
||||
end
|
||||
end
|
||||
end)
|
|
@ -0,0 +1,3 @@
|
|||
name = pathfinding
|
||||
description = Adds the .goto command!
|
||||
author = Fleckenstein
|
|
@ -0,0 +1,3 @@
|
|||
goto_max_distance (Maximum distance from the search positions to search in) int 25
|
||||
goto_max_jump (Jump height) int 1
|
||||
goto_max_drop (Maximum drop height) int 5
|
|
@ -0,0 +1,33 @@
|
|||
perlin = dofile(minetest.get_modpath("perlin") .. "/perlin.lua")
|
||||
|
||||
local start, height, stretch
|
||||
|
||||
minetest.register_chatcommand("perlin", {
|
||||
description = "Start perlin terraforming",
|
||||
param = "<height> <stretch>",
|
||||
func = function(param)
|
||||
local sparam = param:split(" ")
|
||||
start, height, stretch = math.floor(minetest.localplayer:get_pos().y), sparam[1], sparam[2]
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("perlinstop", {
|
||||
description = "Abort perlin terraforming",
|
||||
func = function(param)
|
||||
start, height, stretch = nil
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if start then
|
||||
local player = minetest.localplayer
|
||||
local pos = vector.floor(player:get_pos())
|
||||
for x = pos.x - 1, pos.x + 1 do
|
||||
for z = pos.z - 1, pos.z + 1 do
|
||||
local y = math.floor(start + height * perlin:noise(x / stretch, z / stretch))
|
||||
local p = vector.new(x, y, z)
|
||||
minetest.place_node(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
|
@ -0,0 +1,3 @@
|
|||
name = perlin
|
||||
description = A bot that does terraforming automatically using perlin noise.
|
||||
author = Fleckenstein
|
|
@ -0,0 +1,144 @@
|
|||
--[[
|
||||
Implemented as described here:
|
||||
http://flafla2.github.io/2014/08/09/perlinnoise.html
|
||||
]]--
|
||||
|
||||
local perlin = {}
|
||||
perlin.p = {}
|
||||
|
||||
local bit32 = {}
|
||||
function bit32.band(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Hash lookup table as defined by Ken Perlin
|
||||
-- This is a randomly arranged array of all numbers from 0-255 inclusive
|
||||
local permutation = {151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
|
||||
}
|
||||
|
||||
-- p is used to hash unit cube coordinates to [0, 255]
|
||||
for i=0,255 do
|
||||
-- Convert to 0 based index table
|
||||
perlin.p[i] = permutation[i+1]
|
||||
-- Repeat the array to avoid buffer overflow in hash function
|
||||
perlin.p[i+256] = permutation[i+1]
|
||||
end
|
||||
|
||||
-- Return range: [-1, 1]
|
||||
function perlin:noise(x, y, z)
|
||||
y = y or 0
|
||||
z = z or 0
|
||||
|
||||
-- Calculate the "unit cube" that the point asked will be located in
|
||||
local xi = bit32.band(math.floor(x),255)
|
||||
local yi = bit32.band(math.floor(y),255)
|
||||
local zi = bit32.band(math.floor(z),255)
|
||||
|
||||
-- Next we calculate the location (from 0 to 1) in that cube
|
||||
x = x - math.floor(x)
|
||||
y = y - math.floor(y)
|
||||
z = z - math.floor(z)
|
||||
|
||||
-- We also fade the location to smooth the result
|
||||
local u = self.fade(x)
|
||||
local v = self.fade(y)
|
||||
local w = self.fade(z)
|
||||
|
||||
-- Hash all 8 unit cube coordinates surrounding input coordinate
|
||||
local p = self.p
|
||||
local A, AA, AB, AAA, ABA, AAB, ABB, B, BA, BB, BAA, BBA, BAB, BBB
|
||||
A = p[xi ] + yi
|
||||
AA = p[A ] + zi
|
||||
AB = p[A+1 ] + zi
|
||||
AAA = p[ AA ]
|
||||
ABA = p[ AB ]
|
||||
AAB = p[ AA+1 ]
|
||||
ABB = p[ AB+1 ]
|
||||
|
||||
B = p[xi+1] + yi
|
||||
BA = p[B ] + zi
|
||||
BB = p[B+1 ] + zi
|
||||
BAA = p[ BA ]
|
||||
BBA = p[ BB ]
|
||||
BAB = p[ BA+1 ]
|
||||
BBB = p[ BB+1 ]
|
||||
|
||||
-- Take the weighted average between all 8 unit cube coordinates
|
||||
return self.lerp(w,
|
||||
self.lerp(v,
|
||||
self.lerp(u,
|
||||
self:grad(AAA,x,y,z),
|
||||
self:grad(BAA,x-1,y,z)
|
||||
),
|
||||
self.lerp(u,
|
||||
self:grad(ABA,x,y-1,z),
|
||||
self:grad(BBA,x-1,y-1,z)
|
||||
)
|
||||
),
|
||||
self.lerp(v,
|
||||
self.lerp(u,
|
||||
self:grad(AAB,x,y,z-1), self:grad(BAB,x-1,y,z-1)
|
||||
),
|
||||
self.lerp(u,
|
||||
self:grad(ABB,x,y-1,z-1), self:grad(BBB,x-1,y-1,z-1)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
-- Gradient function finds dot product between pseudorandom gradient vector
|
||||
-- and the vector from input coordinate to a unit cube vertex
|
||||
perlin.dot_product = {
|
||||
[0x0]=function(x,y,z) return x + y end,
|
||||
[0x1]=function(x,y,z) return -x + y end,
|
||||
[0x2]=function(x,y,z) return x - y end,
|
||||
[0x3]=function(x,y,z) return -x - y end,
|
||||
[0x4]=function(x,y,z) return x + z end,
|
||||
[0x5]=function(x,y,z) return -x + z end,
|
||||
[0x6]=function(x,y,z) return x - z end,
|
||||
[0x7]=function(x,y,z) return -x - z end,
|
||||
[0x8]=function(x,y,z) return y + z end,
|
||||
[0x9]=function(x,y,z) return -y + z end,
|
||||
[0xA]=function(x,y,z) return y - z end,
|
||||
[0xB]=function(x,y,z) return -y - z end,
|
||||
[0xC]=function(x,y,z) return y + x end,
|
||||
[0xD]=function(x,y,z) return -y + z end,
|
||||
[0xE]=function(x,y,z) return y - x end,
|
||||
[0xF]=function(x,y,z) return -y - z end
|
||||
}
|
||||
function perlin:grad(hash, x, y, z)
|
||||
return self.dot_product[bit32.band(hash,0xF)](x,y,z)
|
||||
end
|
||||
|
||||
-- Fade function is used to smooth final output
|
||||
function perlin.fade(t)
|
||||
return t * t * t * (t * (t * 6 - 15) + 10)
|
||||
end
|
||||
|
||||
function perlin.lerp(t, a, b)
|
||||
return a + t * (b - a)
|
||||
end
|
||||
|
||||
return perlin
|
|
@ -0,0 +1,16 @@
|
|||
core.register_list_command("xray", "Configure X-Ray", "xray_nodes")
|
||||
core.register_list_command("search", "Configure NodeESP", "node_esp_nodes")
|
||||
|
||||
core.register_on_spawn_particle(function(particle)
|
||||
if core.settings:get_bool("noweather") and particle.texture:sub(1, 12) == "weather_pack" then
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
core.register_on_play_sound(function(sound)
|
||||
if core.settings:get_bool("noweather") and sound.name == "weather_rain" then
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_cheat("NoWeather", "Render", "noweather")
|
|
@ -0,0 +1,48 @@
|
|||
local warp = warp or {set_here = function() return false end}
|
||||
|
||||
local formspec = ""
|
||||
.. "size[11,5.5]"
|
||||
.. "bgcolor[#320000b4;true]"
|
||||
.. "label[4.85,1.35;" .. "You died" .. "]"
|
||||
.. "button_exit[2,3;3,0.5;btn_respawn;" .. "Respawn" .. "]"
|
||||
.. "button_exit[6,3;3,0.5;btn_ghost_mode;" .. "Ghost Mode" .. "]"
|
||||
.. "set_focus[btn_respawn;true]"
|
||||
|
||||
minetest.register_on_death(function()
|
||||
if minetest.settings:get_bool("deathwarp") then
|
||||
local warp_success, warp_msg = warp.set_here("death")
|
||||
if warp_success then
|
||||
minetest.display_chat_message(warp_msg)
|
||||
end
|
||||
end
|
||||
if minetest.settings:get_bool("autorespawn") then
|
||||
minetest.send_respawn()
|
||||
else
|
||||
minetest.show_formspec("respawn:death", formspec)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_formspec_input(function(formname, fields)
|
||||
if formname == "respawn:death" then
|
||||
if fields.btn_ghost_mode then
|
||||
minetest.display_chat_message("You are in ghost mode. Use .respawn to Respawn.")
|
||||
else
|
||||
minetest.send_respawn()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("respawn", {
|
||||
description = "Respawn when in ghost mode",
|
||||
func = function()
|
||||
if minetest.localplayer:get_hp() == 0 then
|
||||
minetest.send_respawn()
|
||||
minetest.display_chat_message("Respawned.")
|
||||
else
|
||||
minetest.display_chat_message("You are not in ghost mode.")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_cheat("AutoRespawn", "Player", "autorespawn")
|
||||
minetest.register_cheat("DeathWarp", "Player", "deathwarp")
|
|
@ -0,0 +1,4 @@
|
|||
name = respawn
|
||||
author = Fleckenstein
|
||||
description = Extended respawn behaviour
|
||||
optional_depends = warp
|
|
@ -0,0 +1 @@
|
|||
autorespawn (AutoRespawn) bool false
|
|
@ -0,0 +1,204 @@
|
|||
local autoeat = rawget(_G, "autoeat") or {}
|
||||
local storage = minetest.get_mod_storage()
|
||||
local pos1, pos2
|
||||
local min, max = math.min, math.max
|
||||
local building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks
|
||||
|
||||
minetest.register_chatcommand("pos1", {
|
||||
description = "Set schematicas position 1 at your current location",
|
||||
func = function()
|
||||
pos1 = vector.round(minetest.localplayer:get_pos())
|
||||
return true, "Position 1 set to " .. minetest.pos_to_string(pos1)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("pos2", {
|
||||
description = "Set schematicas position 2 at your current location",
|
||||
func = function()
|
||||
pos2 = vector.round(minetest.localplayer:get_pos())
|
||||
return true, "Position 2 set to " .. minetest.pos_to_string(pos2)
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
minetest.register_chatcommand("schemesave", {
|
||||
description = "Save a schematica",
|
||||
param = "<name>",
|
||||
func = function(name)
|
||||
if not pos1 or not pos2 then
|
||||
return false, "Position 1 or 2 not set."
|
||||
end
|
||||
|
||||
local data = {}
|
||||
|
||||
local lx, ly, lz, hx, hy, hz = min(pos1.x, pos2.x), min(pos1.y, pos2.y), min(pos1.z, pos2.z), max(pos1.x, pos2.x), max(pos1.y, pos2.y), max(pos1.z, pos2.z)
|
||||
|
||||
for x = lx, hx do
|
||||
local rx = x - lx
|
||||
for y = ly, hy do
|
||||
local ry = y - ly
|
||||
for z = lz, hz do
|
||||
local rz = z - lz
|
||||
local node = minetest.get_node_or_nil({x = x, y = y, z = z})
|
||||
if node and node.name ~= "air" then
|
||||
table.insert(data, {pos = {x = rx, y = ry, z = rz}, node = node.name})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
storage:set_string(name, minetest.serialize(data))
|
||||
return true, "Scheme saved successfully as '" .. name .. "'."
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemebuild", {
|
||||
description = "Build a schematica",
|
||||
param = "<name>",
|
||||
func = function(name)
|
||||
if not pos1 then
|
||||
return false, "Position 1 not set."
|
||||
end
|
||||
if building then
|
||||
return false, "Still building a scheme. Use .schemeabort to stop it."
|
||||
end
|
||||
local rawdata = storage:get(name)
|
||||
if not rawdata then
|
||||
return false, "Schematica '" .. name .. "' not found."
|
||||
end
|
||||
building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = true, 1, minetest.deserialize(rawdata), vector.new(pos1), false, 0, false
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemerecipe", {
|
||||
description = "Print the recipe for a schematica",
|
||||
param = "<name>",
|
||||
func = function(name)
|
||||
local rawdata = storage:get(name)
|
||||
if not rawdata then
|
||||
return false, "Schematica '" .. name .. "' not found."
|
||||
end
|
||||
local data = minetest.deserialize(rawdata)
|
||||
local sorted = {}
|
||||
for _, d in ipairs(data) do
|
||||
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemeresume", {
|
||||
description = "Resume constructing a schematica",
|
||||
func = function()
|
||||
if not build_data then
|
||||
return false, "Currently not building a scheme."
|
||||
end
|
||||
building, out_of_blocks = true, false
|
||||
return true, "Resumed."
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemepause", {
|
||||
description = "Pause constructing a schematica",
|
||||
func = function()
|
||||
if not build_data then
|
||||
return false, "Currently not building a scheme."
|
||||
end
|
||||
building = false
|
||||
return true, "Paused."
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemeabort", {
|
||||
description = "Abort constructing a schematica",
|
||||
param = "<name>",
|
||||
func = function()
|
||||
if not build_data then
|
||||
return false, "Currently not building a scheme."
|
||||
end
|
||||
building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nilw
|
||||
return true, "Aborted."
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemeskip", {
|
||||
description = "Skip a step in constructing a schematica",
|
||||
param = "<name>",
|
||||
func = function()
|
||||
if not build_data then
|
||||
return false, "Currently not building a scheme."
|
||||
end
|
||||
building, build_index = true, build_index + 1
|
||||
return true, "Skipped."
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemegetindex", {
|
||||
description = "Output the build index of the schematica",
|
||||
func = function()
|
||||
return build_index and true or false, build_index
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("schemesetindex", {
|
||||
description = "Set the build index of the schematica",
|
||||
param = "<index>",
|
||||
func = function(param)
|
||||
local index = tonumber(param)
|
||||
if not index then return false, "Invalid usage." end
|
||||
build_index = index
|
||||
return true, "Index Changed"
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if building and not autoeat.eating then
|
||||
local data = build_data[build_index]
|
||||
if not data then
|
||||
building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nil
|
||||
minetest.display_chat_message("Completed Schematica.")
|
||||
return
|
||||
end
|
||||
local pos, node = vector.add(build_pos, data.pos), data.node
|
||||
if just_placed_node then
|
||||
local map_node = minetest.get_node_or_nil(pos)
|
||||
if map_node and map_node.name == node then
|
||||
build_index = build_index + 1
|
||||
just_placed_node = false
|
||||
else
|
||||
failed_count = failed_count + 1
|
||||
end
|
||||
if failed_count < 10 then
|
||||
return
|
||||
end
|
||||
end
|
||||
failed_count = 0
|
||||
local new_index
|
||||
local inventory = minetest.get_inventory("current_player").main
|
||||
for index, stack in ipairs(inventory) do
|
||||
if minetest.get_item_def(stack:get_name()).node_placement_prediction == node then
|
||||
new_index = index - 1
|
||||
break
|
||||
end
|
||||
end
|
||||
if not new_index then
|
||||
if not out_of_blocks then
|
||||
minetest.display_chat_message("Out of blocks for schematica. Missing ressource: '" .. node .. "'. It will resume as soon as you got it or use .schemeskip to skip it.")
|
||||
minetest.send_chat_message("[Schematicas] Missing ressource: " .. node)
|
||||
end
|
||||
out_of_blocks = true
|
||||
return
|
||||
end
|
||||
if out_of_blocks then
|
||||
minetest.send_chat_message("[Schematicas] Resuming.")
|
||||
end
|
||||
out_of_blocks = false
|
||||
minetest.localplayer:set_wield_index(new_index)
|
||||
minetest.localplayer:set_pos(minetest.find_node_near(pos, 5, {"air", "ignore", "mcl_core:water_source", "mcl_core:water_flowing"}, false) or pos)
|
||||
minetest.place_node(pos)
|
||||
just_placed_node = true
|
||||
if build_index % 250 == 0 then
|
||||
minetest.send_chat_message("[Schematicas] " .. build_index .. " of " .. #build_data .. " blocks placed!")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
name = schematicas
|
||||
description = Save structures and recreate them automatically in survival.
|
||||
author = Fleckenstein
|
||||
optional_depends = autoeat
|
|
@ -0,0 +1,94 @@
|
|||
warp = {}
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
|
||||
function warp.set(warp, pos)
|
||||
if warp == "" or not pos then return false, "Missing parameter." end
|
||||
local posstr = minetest.pos_to_string(pos)
|
||||
storage:set_string(warp, posstr)
|
||||
return true, "Warp " .. warp .. " set to " .. posstr .. "."
|
||||
end
|
||||
|
||||
function warp.set_here(param)
|
||||
local success, message = warp.set(param, vector.round(minetest.localplayer:get_pos()))
|
||||
return success, message
|
||||
end
|
||||
|
||||
function warp.get(param)
|
||||
if param == "" then return false, "Missing parameter." end
|
||||
local pos = storage:get_string(param)
|
||||
if pos == "" then return false, "Warp " .. param .. " not set." end
|
||||
return true, "Warp " .. param .. " is set to " .. pos .. ".", minetest.string_to_pos(pos)
|
||||
end
|
||||
|
||||
function warp.delete(param)
|
||||
if param == "" then return false, "Missing parameter." end
|
||||
storage:set_string(param, "")
|
||||
return true, "Deleted warp " .. param .. "."
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("setwarp", {
|
||||
params = "<warp>",
|
||||
description = "Set a warp to your current position.",
|
||||
func = warp.set_here,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("readwarp", {
|
||||
params = "<warp>",
|
||||
description = "Print the coordinates of a warp.",
|
||||
func = warp.get,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("deletewarp", {
|
||||
params = "<warp>",
|
||||
description = "Delete a warp.",
|
||||
func = warp.delete,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("listwarps", {
|
||||
description = "List all warps.",
|
||||
func = function()
|
||||
local warps = storage:to_table().fields
|
||||
local warplist = {}
|
||||
for warp in pairs(warps) do
|
||||
table.insert(warplist, warp)
|
||||
end
|
||||
if #warplist > 0 then
|
||||
return true, table.concat(warplist, ", ")
|
||||
else
|
||||
return false, "No warps set."
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
local function do_warp(param)
|
||||
if param == "" then return false, "Missing parameter." end
|
||||
local success, pos = minetest.parse_pos(param)
|
||||
if not success then
|
||||
local msg
|
||||
success, msg, pos = warp.get(param)
|
||||
if not success then
|
||||
return false, msg
|
||||
end
|
||||
end
|
||||
minetest.localplayer:set_pos(pos)
|
||||
return true, "Warped to " .. minetest.pos_to_string(pos)
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("warp", {
|
||||
params = "<pos>|<warp>",
|
||||
description = "Warp to a set warp or a position.",
|
||||
func = do_warp
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("warpandexit", {
|
||||
params = "<pos>|<warp>",
|
||||
description = "Warp to a set warp or a position and exit.",
|
||||
func = function(param)
|
||||
local s, m = do_warp(param)
|
||||
if s then
|
||||
minetest.disconnect()
|
||||
end
|
||||
return s,m
|
||||
end
|
||||
})
|
|
@ -0,0 +1,3 @@
|
|||
name = warp
|
||||
author = Fleckenstein
|
||||
description = Set custom warps and use the teleport exploit
|
|
@ -0,0 +1,170 @@
|
|||
function sleep(s)
|
||||
local ntime = os.clock() + s/10
|
||||
repeat until os.clock() > ntime
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("findnodes", {
|
||||
description = "Scan for one or multible nodes in a radius around you",
|
||||
param = "<radius> <node1>[,<node2>...]",
|
||||
func = function(param)
|
||||
local radius = tonumber(param:split(" ")[1])
|
||||
local nodes = param:split(" ")[2]:split(",")
|
||||
local pos = minetest.localplayer:get_pos()
|
||||
local fpos = minetest.find_node_near(pos, radius, nodes, true)
|
||||
if fpos then
|
||||
return true, "Found " .. table.concat(nodes, " or ") .. " at " .. minetest.pos_to_string(fpos)
|
||||
end
|
||||
return false, "None of " .. table.concat(nodes, " or ") .. " found in a radius of " .. tostring(radius)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("place", {
|
||||
params = "<X>,<Y>,<Z>",
|
||||
description = "Place wielded item",
|
||||
func = function(param)
|
||||
local success, pos = minetest.parse_relative_pos(param)
|
||||
if success then
|
||||
minetest.place_node(pos)
|
||||
return true, "Node placed at " .. minetest.pos_to_string(pos)
|
||||
end
|
||||
return false, pos
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("screenshot", {
|
||||
description = "asdf",
|
||||
func = function()
|
||||
minetest.take_screenshot()
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("dig", {
|
||||
params = "<X>,<Y>,<Z>",
|
||||
description = "Dig node",
|
||||
func = function(param)
|
||||
local success, pos = minetest.parse_relative_pos(param)
|
||||
if success then
|
||||
minetest.dig_node(pos)
|
||||
return true, "Node at " .. minetest.pos_to_string(pos) .. " dug"
|
||||
end
|
||||
return false, pos
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_on_dignode(function(pos)
|
||||
if minetest.settings:get_bool("replace") then
|
||||
minetest.after(0, minetest.place_node, pos)
|
||||
end
|
||||
end)
|
||||
|
||||
local etime = 0
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
etime = etime + dtime
|
||||
if etime < 1 then return end
|
||||
local player = minetest.localplayer
|
||||
if not player then return end
|
||||
local pos = player:get_pos()
|
||||
local item = player:get_wielded_item()
|
||||
local def = minetest.get_item_def(item:get_name())
|
||||
local nodes_per_tick = tonumber(minetest.settings:get("nodes_per_tick")) or 8
|
||||
if item:get_count() > 0 and def.node_placement_prediction ~= "" then
|
||||
if minetest.settings:get_bool("scaffold") then
|
||||
local p = vector.round(vector.add(pos, {x = 0, y = -0.6, z = 0}))
|
||||
local node = minetest.get_node_or_nil(p)
|
||||
if not node or minetest.get_node_def(node.name).buildable_to then
|
||||
minetest.place_node(p)
|
||||
end
|
||||
elseif minetest.settings:get_bool("mscaffold") then
|
||||
--local z = pos.z
|
||||
local positions = {
|
||||
{x = 0, y = -0.6, z = 0},
|
||||
{x = 1, y = -0.6, z = 0},
|
||||
{x = -1, y = -0.6, z = 0},
|
||||
|
||||
{x = -1, y = -0.6, z = -1},
|
||||
{x = 0, y = -0.6, z = -1},
|
||||
{x = 1, y = -0.6, z = -1},
|
||||
|
||||
{x = -1, y = -0.6, z = 1},
|
||||
{x = 0, y = -0.6, z = 1},
|
||||
{x = 1, y = -0.6, z = 1}
|
||||
|
||||
}
|
||||
for i, p in pairs(positions) do
|
||||
if i > nodes_per_tick then return end
|
||||
minetest.place_node(vector.add(pos,p))
|
||||
end
|
||||
|
||||
elseif minetest.settings:get_bool("highway_z") then
|
||||
local z = pos.z
|
||||
local positions = {
|
||||
{x = 0, y = 0, z = z},
|
||||
{x = 1, y = 0, z = z},
|
||||
{x = 2, y = 1, z = z},
|
||||
{x = -2, y = 1, z = z},
|
||||
{x = -2, y = 0, z = z},
|
||||
{x = -1, y = 0, z = z},
|
||||
{x = 2, y = 0, z = z}
|
||||
}
|
||||
for i, p in pairs(positions) do
|
||||
if i > nodes_per_tick then break end
|
||||
minetest.place_node(p)
|
||||
end
|
||||
elseif minetest.settings:get_bool("block_water") then
|
||||
local positions = minetest.find_nodes_near(pos, 5, {"mcl_core:water_source", "mcl_core:water_flowing"}, true)
|
||||
for i, p in pairs(positions) do
|
||||
if i > nodes_per_tick then return end
|
||||
minetest.place_node(p)
|
||||
end
|
||||
elseif minetest.settings:get_bool("block_lava") then
|
||||
local positions = minetest.find_nodes_near(pos, 5, {"mcl_core:lava_source", "mcl_core:lava_flowing"}, true)
|
||||
for i, p in pairs(positions) do
|
||||
if i > nodes_per_tick then return end
|
||||
minetest.place_node(p)
|
||||
end
|
||||
elseif minetest.settings:get_bool("block_sources") then
|
||||
local positions = minetest.find_nodes_near(pos, 5, {"mcl_core:lava_source","mcl_nether:nether_lava_source","mcl_core:water_source"}, true)
|
||||
for i, p in pairs(positions) do
|
||||
if p.y<2 then
|
||||
if p.x>500 and p.z>500 then return end
|
||||
end
|
||||
|
||||
if i > nodes_per_tick then return end
|
||||
minetest.place_node(p)
|
||||
end
|
||||
elseif minetest.settings:get_bool("autotnt") then
|
||||
local positions = minetest.find_nodes_near_under_air_except(pos, 5, item:get_name(), true)
|
||||
for i, p in pairs(positions) do
|
||||
if i > nodes_per_tick then break end
|
||||
minetest.place_node(vector.add(p, {x = 0, y = 1, z = 0}))
|
||||
end
|
||||
end
|
||||
end
|
||||
if minetest.settings:get_bool("nuke") then
|
||||
local i = 0
|
||||
for x = pos.x - 4, pos.x + 4 do
|
||||
for y = pos.y - 4, pos.y + 4 do
|
||||
for z = pos.z - 4, pos.z + 4 do
|
||||
local p = vector.new(x, y, z)
|
||||
local node = minetest.get_node_or_nil(p)
|
||||
local def = node and minetest.get_node_def(node.name)
|
||||
if def and def.diggable then
|
||||
if i > nodes_per_tick then return end
|
||||
minetest.dig_node(p)
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_cheat("mScaffold", "World", "mscaffold")
|
||||
minetest.register_cheat("Scaffold", "World", "scaffold")
|
||||
minetest.register_cheat("HighwayZ", "World", "highway_z")
|
||||
minetest.register_cheat("BlockWater", "World", "block_water")
|
||||
minetest.register_cheat("BlockLava", "World", "block_lava")
|
||||
minetest.register_cheat("BlockSrc", "World", "block_sources")
|
||||
minetest.register_cheat("PlaceOnTop", "World", "autotnt")
|
||||
minetest.register_cheat("Replace", "World", "replace")
|
||||
minetest.register_cheat("Nuke", "World", "nuke")
|
|
@ -0,0 +1,3 @@
|
|||
name = world
|
||||
desciption = Adds several world interaction bots to dragonfire.
|
||||
author = Fleckenstein
|
|
@ -0,0 +1,6 @@
|
|||
scaffold (Scaffold) bool false
|
||||
highway_z (HighwayZ) bool false
|
||||
block_water (BlockWater) bool false
|
||||
autotnt (AutoTNT) bool false
|
||||
replace (Replace) bool false
|
||||
nodes_per_tick (Number of nodes to place per tick) int 8
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Benjamin Fleming
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,59 @@
|
|||
# CSM DTE
|
||||
## Client Side Mod Designing & Testing Environment
|
||||
An advanced, ingame lua and formspec editor for minetest.
|
||||
|
||||
This can be used for creating, testing and using CSMs without reloading the game, and without the game crashing.
|
||||
This is also the easiest way to create advanced formspecs.
|
||||
It was tested with multiple CSMs from the minetest forums, and they all worked. (actually in the current version, a few things might not work, but they will be fixed in the future)
|
||||
|
||||
CSMs can be created, or pasted in, and they should work the same as they would normaly, except errors won't crash the game!
|
||||
|
||||
functions that are registered with minetest can be put in a function `safe(func)` to output errors to the UI when minetest calls them
|
||||
|
||||
scripts can be put in startup to run them automatically when the game loads. errors are also put in the UI
|
||||
|
||||
screenshots:
|
||||
![lua editor](preview_1.png)
|
||||
![formspec editor](preview_2.png)
|
||||
|
||||
## FEATURES:
|
||||
lua editor:
|
||||
- print function
|
||||
- coloured error output
|
||||
- multiple files
|
||||
- file creation and deletion
|
||||
- safe function execution
|
||||
- automatically run files at startup
|
||||
|
||||
formspec editor:
|
||||
- every widget is available
|
||||
- widgets are easy to edit
|
||||
- formspec preview, shows what it will look like
|
||||
- export as a function with parameters
|
||||
- export as a string
|
||||
- and a whole bunch of fancy stuff
|
||||
|
||||
## To Use:
|
||||
- use the command `.dte` to open the editor
|
||||
- select the `lua editor` tab to run and edit CSMs
|
||||
- select the `formspec editor` tab to create a formspec
|
||||
- select the `files` tab to open, create, and delete files
|
||||
- select the `startup` tab to select lua files to run when the game loads
|
||||
|
||||
## How to install
|
||||
- make sure you have client modding enabled (search for `client modding` in advanced settings, and set it to true)
|
||||
- download and extract the zip file into `clientmods\csm_dte` or paste the `init.lua` file into it.
|
||||
- add `load_mod_csm_dte = true` to the `clientmods\mods.conf` file
|
||||
- join a game or server, and it should work!
|
||||
|
||||
## Editing the files
|
||||
### - if you do not wan't to edit the program, the `development` folder can be deleted!
|
||||
when editing the program, it is easier to edit the smaller files found inside the `development` folder.
|
||||
these can be run as seperate CSMs for testing (I recomend disabling `csm_dte`)
|
||||
to join the together, copy the lua editor into `csm_dte/init.lua` and copy the formspec editor (from EDITOR START to EDITOR END) into the "PASTE FORMSPEC EDITOR HERE" section
|
||||
|
||||
### TODO:
|
||||
- make all functions work after the game has been loaded
|
||||
- add a UI to unregister functions which were registered from a program
|
||||
- add a lua console
|
||||
- import ui strings into the editor (?)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,492 @@
|
|||
local data = { -- window size
|
||||
width = 15,
|
||||
height = 10,
|
||||
|
||||
}
|
||||
local form_esc = minetest.formspec_escape -- shorten the function
|
||||
|
||||
local modstorage = core.get_mod_storage()
|
||||
|
||||
|
||||
local function create_tabs(selected)
|
||||
return "tabheader[0,0;_option_tabs_;" ..
|
||||
" LUA EDITOR ,FORMSPEC EDITOR, LUA CONSOLE , FILES , STARTUP , FUNCTIONS , HELP ;"..selected..";;]"
|
||||
end
|
||||
|
||||
local function copy_table(table)
|
||||
local new = {}
|
||||
for i, v in pairs(table) do
|
||||
if type(v) == "table" then
|
||||
v = copy_table(v)
|
||||
end
|
||||
new[i] = v
|
||||
end
|
||||
return new
|
||||
end
|
||||
|
||||
|
||||
----------
|
||||
-- LOAD AND DEFINE STUFF - global stuff is accissible from the UI
|
||||
----------
|
||||
|
||||
local split = function (str, splitter) -- a function to split a string into a list. "\" before the splitter makes it ignore it (usefull for minetests formspecs)
|
||||
local result = {""}
|
||||
for i=1, str:len() do
|
||||
char = string.sub(str, i, i)
|
||||
if char == splitter and string.sub(str, i-1, i-1) ~= "\\" then
|
||||
table.insert(result, "")
|
||||
else
|
||||
result[#result] = result[#result]..char
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
local output = {} -- the output for errors, prints, etc
|
||||
|
||||
local saved_file = modstorage:get_string("_lua_saved") -- remember what file is currently being edited
|
||||
if saved_file == "" then
|
||||
saved_file = false -- if the file had no save name (it was still saved)
|
||||
end
|
||||
|
||||
|
||||
local lua_startup = split(modstorage:get_string("_lua_startup"), ",") -- the list of scripts to run at startup
|
||||
|
||||
local lua_files = split(modstorage:get_string("_lua_files_list"), ",") -- the list of names of all saved files
|
||||
|
||||
local ui_files = split(modstorage:get_string("_UI_files_list"), ",") -- UI files list
|
||||
|
||||
local reg_funcs = {formspec_input={}, chatcommands={}, on_connect={}, joinplayer={}, sending_chat_message={}, recieving_chat_message={}}
|
||||
|
||||
|
||||
local selected_files = {0, 0}
|
||||
|
||||
|
||||
minetest.register_on_connect(function() -- some functions don't work after startup. this tries to replace them
|
||||
|
||||
minetest.get_mod_storage = function()
|
||||
return modstorage
|
||||
end
|
||||
|
||||
core.get_mod_storage = function()
|
||||
return modstorage
|
||||
end
|
||||
|
||||
-- show formspec
|
||||
|
||||
end) -- add whatever functions don't work after startup to here (if possible)
|
||||
|
||||
|
||||
----------
|
||||
-- FUNCTIONS FOR UI
|
||||
----------
|
||||
|
||||
function print(...) -- replace print to output into the UI. (doesn't refresh untill the script has ended)
|
||||
params = {...}
|
||||
if #params == 1 then
|
||||
local str = params[1]
|
||||
if type(str) ~= "string" then
|
||||
str = dump(str)
|
||||
end
|
||||
table.insert(output, "")
|
||||
for i=1, str:len() do
|
||||
char = string.sub(str, i, i)
|
||||
if char == "\n" then
|
||||
table.insert(output, "") -- split multiple lines over multiple lines. without this, text with line breaks would not display properly
|
||||
else
|
||||
output[#output] = output[#output]..char
|
||||
end
|
||||
end
|
||||
else
|
||||
for i, v in pairs(params) do
|
||||
print(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function safe(func) -- run a function without crashing the game. All errors are displayed in the UI.
|
||||
f = function(...) -- This can be used for functions being registered with minetest, like "minetest.register_chat_command()"
|
||||
status, out = pcall(func, ...)
|
||||
if status then
|
||||
return out
|
||||
else
|
||||
table.insert(output, "#ff0000Error: "..out)
|
||||
minetest.debug("Error (func): "..out)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
|
||||
----------
|
||||
-- CODE EXECUTION
|
||||
----------
|
||||
|
||||
local function run(code, name) -- run a script
|
||||
if name == nil then
|
||||
name = saved_file
|
||||
end
|
||||
status, err = pcall(loadstring(code)) -- run
|
||||
if status then
|
||||
if saved_file == false then
|
||||
table.insert(output, "#00ff00finished") -- display that the script ran without errors
|
||||
else
|
||||
table.insert(output, "#00ff00"..name..": finished") -- display which script, if it was saved
|
||||
end
|
||||
else
|
||||
if err == "attempt to call a nil value" then
|
||||
err = "Syntax Error"
|
||||
end
|
||||
if saved_file == false then
|
||||
table.insert(output, "#ff0000Error: "..err) -- display errors
|
||||
minetest.log("Error (unsaved): "..err)
|
||||
else
|
||||
table.insert(output, "#ff0000"..name..": Error: "..err)
|
||||
minetest.log("Error ("..name.."): "..err)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function on_startup() -- ran on startup. Runs all scripts registered for startup
|
||||
for i, v in pairs(lua_startup) do
|
||||
if v ~= "" then
|
||||
run(modstorage:get_string("_lua_file_"..v, v), v) -- errors still get displayed in the UI
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
on_startup()
|
||||
|
||||
|
||||
----------
|
||||
-- FILE READING AND SAVING
|
||||
----------
|
||||
|
||||
local function load_lua() -- returns the contents of the file currently being edited
|
||||
if saved_file == false then
|
||||
return modstorage:get_string("_lua_temp") -- unsaved files are remembered (get saved on UI reloads - when clicking on buttons)
|
||||
else
|
||||
return modstorage:get_string("_lua_file_"..saved_file)
|
||||
end
|
||||
end
|
||||
|
||||
local function save_lua(code) -- save a file
|
||||
if saved_file == false then
|
||||
modstorage:set_string("_lua_temp", code)
|
||||
else
|
||||
modstorage:set_string("_lua_file_"..saved_file, code)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
----------
|
||||
-- FORM DEFINITIONS
|
||||
----------
|
||||
|
||||
|
||||
local function startup_form() -- the formspec for adding or removing files for startup
|
||||
local startup_str = ""
|
||||
for i, v in pairs(lua_startup) do
|
||||
if i ~= 1 then startup_str = startup_str.."," end
|
||||
startup_str = startup_str .. form_esc(v)
|
||||
end
|
||||
local files_str = ""
|
||||
for i, v in pairs(lua_files) do
|
||||
if i ~= 1 then files_str = files_str.."," end
|
||||
files_str = files_str .. form_esc(v)
|
||||
end
|
||||
|
||||
local form = ""..
|
||||
"size["..data.width..","..data.height.."]" ..
|
||||
"label[0,0.1;Startup Items:]"..
|
||||
"label["..data.width/2 ..",0.1;File List:]"..
|
||||
"textlist[0,0.5;"..data.width/2-0.1 ..","..data.height-1 ..";starts;"..startup_str.."]"..
|
||||
"textlist["..data.width/2 ..",0.5;"..data.width/2-0.1 ..","..data.height-1 ..";chooser;"..files_str.."]"..
|
||||
"label[0," .. data.height-0.3 .. ";double click items to add or remove from startup]"..
|
||||
|
||||
"" .. create_tabs(5)
|
||||
return form
|
||||
end
|
||||
|
||||
|
||||
local function lua_editor() -- the main formspec for editing
|
||||
|
||||
local output_str = "" -- convert the output to a string
|
||||
for i, v in pairs(output) do
|
||||
if output_str:len() > 0 then output_str = output_str .. "," end
|
||||
output_str = output_str .. form_esc(v)
|
||||
end
|
||||
|
||||
local code = form_esc(load_lua())
|
||||
|
||||
-- create the form
|
||||
local form = ""..
|
||||
"size["..data.width..","..data.height.."]" ..
|
||||
"textarea[0.3,0.1;"..data.width ..","..data.height-3 ..";editor;Lua editor;"..code.."]"..
|
||||
"button[0," .. data.height-3.5 .. ";1,0;run;RUN]"..
|
||||
"button[1," .. data.height-3.5 .. ";1,0;clear;CLEAR]"..
|
||||
"button[2," .. data.height-3.5 .. ";1,0;save;SAVE]"..
|
||||
"textlist[0,"..data.height-3 ..";"..data.width-0.2 ..","..data.height-7 ..";output;"..output_str..";".. #output .."]"..
|
||||
|
||||
"" .. create_tabs(1)
|
||||
return form
|
||||
end
|
||||
|
||||
|
||||
local function file_viewer() -- created with the formspec editor!
|
||||
local lua_files_item_str = ""
|
||||
for i, item in pairs(lua_files) do
|
||||
if i ~= 1 then lua_files_item_str = lua_files_item_str.."," end
|
||||
lua_files_item_str = lua_files_item_str .. form_esc(item)
|
||||
end
|
||||
|
||||
local ui_select_item_str = ""
|
||||
for i, item in pairs(ui_files) do
|
||||
if i ~= 1 then ui_select_item_str = ui_select_item_str.."," end
|
||||
ui_select_item_str = ui_select_item_str .. form_esc(item)
|
||||
end
|
||||
|
||||
local form = "" ..
|
||||
"size["..data.width..","..data.height.."]" ..
|
||||
"textlist[-0.2,0.2;"..data.width/2.02- -0.2 ..","..data.height- 1 ..";lua_select;"..lua_files_item_str.."]" ..
|
||||
"label[-0.2,-0.2;LUA FILES]" ..
|
||||
"field[0.1,"..data.height- 0.2 ..";3,1;new_lua;NEW;]" ..
|
||||
"field_close_on_enter[new_lua;false]" ..
|
||||
"button[2.6,"..data.height- 0.5 ..";0.5,1;add_lua;+]" ..
|
||||
"textlist["..data.width/1.97 ..",0.2;"..data.width- 0-(data.width/1.97) ..","..data.height- 1 ..";ui_select;"..ui_select_item_str.."]" ..
|
||||
"label["..data.width/1.96 ..",-0.2;FORMSPEC FILES]" ..
|
||||
"field["..data.width- 2.8 ..","..data.height- 0.2 ..";3,1;new_ui;NEW;]" ..
|
||||
"field_close_on_enter[new_ui;false]" ..
|
||||
"button["..data.width- 0.3 ..","..data.height- 0.5 ..";0.5,1;add_ui;+]" ..
|
||||
"label["..data.width/2.4 ..","..data.height- 0.8 ..";Double click a file to open it]" ..
|
||||
"button[3.1,"..data.height- 0.5 ..";1.1,1;del_lua;DELETE]" ..
|
||||
"button["..data.width- 4.2 ..","..data.height- 0.5 ..";1.1,1;del_ui;DELETE]" ..
|
||||
"" .. create_tabs(4)
|
||||
|
||||
return form
|
||||
end
|
||||
|
||||
|
||||
----------
|
||||
-- FUNCTIONALITY
|
||||
----------
|
||||
|
||||
minetest.register_on_formspec_input(function(formname, fields)
|
||||
|
||||
-- EDITING PAGE
|
||||
----------
|
||||
if formname == "lua:editor" then
|
||||
if fields.run then --[RUN] button
|
||||
save_lua(fields.editor)
|
||||
run(fields.editor)
|
||||
|
||||
minetest.show_formspec("lua:editor", lua_editor())
|
||||
|
||||
elseif fields.save then --[SAVE] button
|
||||
if saved_file == false then
|
||||
modstorage:set_string("_lua_temp", fields.editor)
|
||||
else
|
||||
modstorage:set_string("_lua_file_"..saved_file, fields.editor)
|
||||
end
|
||||
|
||||
elseif fields.clear then --[CLEAR] button
|
||||
output = {}
|
||||
save_lua(fields.editor)
|
||||
minetest.show_formspec("lua:editor", lua_editor())
|
||||
end
|
||||
|
||||
-- STARTUP EDITOR
|
||||
----------
|
||||
elseif formname == "lua:startup" then -- double click a file to remove it from the list
|
||||
if fields.starts then
|
||||
local select = {["type"] = string.sub(fields.starts, 1, 3), ["row"] = tonumber(string.sub(fields.starts, 5, 5))}
|
||||
if select.type == "DCL" then
|
||||
table.remove(lua_startup, select.row)
|
||||
local startup_str = ""
|
||||
for i, v in pairs(lua_startup) do
|
||||
if v ~= "" then
|
||||
startup_str = startup_str..v..","
|
||||
end
|
||||
end
|
||||
modstorage:set_string("_lua_startup", startup_str)
|
||||
minetest.show_formspec("lua:startup", startup_form())
|
||||
end
|
||||
|
||||
elseif fields.chooser then -- double click a file to add it to the list
|
||||
local select = {["type"] = string.sub(fields.chooser, 1, 3), ["row"] = tonumber(string.sub(fields.chooser, 5, 5))}
|
||||
if select.type == "DCL" then
|
||||
table.insert(lua_startup, lua_files[select.row])
|
||||
local startup_str = ""
|
||||
for i, v in pairs(lua_startup) do
|
||||
if v ~= "" then
|
||||
startup_str = startup_str..v..","
|
||||
end
|
||||
end
|
||||
modstorage:set_string("_lua_startup", startup_str)
|
||||
minetest.show_formspec("lua:startup", startup_form())
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
---------- ----------
|
||||
-- PASTE FORMSPEC EDITOR HERE --
|
||||
---------- ----------
|
||||
|
||||
|
||||
--
|
||||
|
||||
|
||||
---------- ----------
|
||||
-- PASTE FORMSPEC EDITOR HERE --
|
||||
---------- ----------
|
||||
|
||||
|
||||
|
||||
|
||||
----------
|
||||
-- UI FUNCTIONALITY
|
||||
----------
|
||||
|
||||
minetest.register_on_formspec_input(function(formname, fields)
|
||||
-- FILE VIEWER
|
||||
----------
|
||||
if formname == "files:viewer" then
|
||||
if fields.del_lua then
|
||||
name = lua_files[selected_files[1] ]
|
||||
table.remove(lua_files, selected_files[1])
|
||||
files_str = ""
|
||||
for i, v in pairs(lua_files) do
|
||||
if v ~= "" then
|
||||
files_str = files_str..v.."," -- remove the file from the list
|
||||
end
|
||||
end
|
||||
|
||||
if name == saved_file then -- clear the editing area if the file was loaded
|
||||
saved_file = false
|
||||
modstorage:set_string("_lua_saved", "")
|
||||
save_lua("")
|
||||
end
|
||||
|
||||
modstorage:set_string("_lua_files_list", files_str)
|
||||
minetest.show_formspec("files:viewer", file_viewer())
|
||||
|
||||
elseif fields.del_ui then
|
||||
name = ui_files[selected_files[2] ]
|
||||
table.remove(ui_files, selected_files[2])
|
||||
files_str = ""
|
||||
for i, v in pairs(ui_files) do
|
||||
if v ~= "" then
|
||||
files_str = files_str..v.."," -- remove the file from the list
|
||||
end
|
||||
end
|
||||
|
||||
if name == current_ui_file then -- clear the editing area if the file was loaded
|
||||
load_UI("new")
|
||||
end
|
||||
|
||||
modstorage:set_string("_UI_files_list", files_str)
|
||||
minetest.show_formspec("files:viewer", file_viewer())
|
||||
|
||||
elseif fields.lua_select then -- click on a file to select it, double click to open it
|
||||
local index = tonumber(string.sub(fields.lua_select, 5))
|
||||
if string.sub(fields.lua_select, 1, 3) == "DCL" then
|
||||
saved_file = lua_files[index]
|
||||
|
||||
modstorage:set_string("_lua_saved", saved_file)
|
||||
minetest.show_formspec("lua:editor", lua_editor())
|
||||
else
|
||||
selected_files[1] = index
|
||||
minetest.show_formspec("files:viewer", file_viewer())
|
||||
end
|
||||
|
||||
elseif fields.ui_select then -- click on a file to select it, double click to open it
|
||||
local index = tonumber(string.sub(fields.ui_select, 5))
|
||||
if string.sub(fields.ui_select, 1, 3) == "DCL" then
|
||||
load_UI(ui_files[index])
|
||||
reload_ui()
|
||||
else
|
||||
selected_files[2] = index
|
||||
minetest.show_formspec("files:viewer", file_viewer())
|
||||
end
|
||||
|
||||
elseif fields.key_enter_field == "new_lua" or fields.add_lua then
|
||||
local exist = false
|
||||
for i, v in pairs(lua_files) do
|
||||
if v == fields.new_lua then
|
||||
exist = true
|
||||
selected_files[1] = i
|
||||
end
|
||||
end
|
||||
if not exist then
|
||||
table.insert(lua_files, fields.new_lua)
|
||||
selected_files[1] = #lua_files
|
||||
|
||||
files_str = ""
|
||||
for i, v in pairs(lua_files) do
|
||||
if v ~= "" then
|
||||
files_str = files_str..v..","
|
||||
end
|
||||
end
|
||||
modstorage:set_string("_lua_files_list", files_str)
|
||||
saved_file = fields.new_lua
|
||||
minetest.show_formspec("lua:editor", lua_editor())
|
||||
end
|
||||
|
||||
elseif fields.key_enter_field == "new_ui" or fields.add_ui then
|
||||
local exist = false
|
||||
for i, v in pairs(ui_files) do
|
||||
if v == fields.new_ui then
|
||||
exist = true
|
||||
selected_files[2] = i
|
||||
end
|
||||
end
|
||||
if not exist then
|
||||
table.insert(ui_files, fields.new_ui)
|
||||
selected_files[2] = #ui_files
|
||||
|
||||
files_str = ""
|
||||
for i, v in pairs(ui_files) do
|
||||
if v ~= "" then
|
||||
files_str = files_str..v..","
|
||||
end
|
||||
end
|
||||
modstorage:set_string("_UI_files_list", files_str)
|
||||
load_UI(fields.new_ui)
|
||||
reload_ui()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if fields._option_tabs_ then
|
||||
if fields._option_tabs_ == "1" then
|
||||
minetest.show_formspec("lua:editor", lua_editor())
|
||||
elseif fields._option_tabs_ == "2" then
|
||||
reload_ui()
|
||||
elseif fields._option_tabs_ == "4" then
|
||||
minetest.show_formspec("files:viewer", file_viewer())
|
||||
elseif fields._option_tabs_ == "5" then
|
||||
minetest.show_formspec("lua:startup", startup_form())
|
||||
else
|
||||
minetest.show_formspec("lua:unknown",
|
||||
"size["..data.width..","..data.height.."]label[1,1;COMING SOON]"..create_tabs(fields._option_tabs_))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
----------
|
||||
-- REGISTER COMMAND
|
||||
----------
|
||||
core.register_chatcommand("dte", { -- register the chat command
|
||||
description = core.gettext("open a lua IDE"),
|
||||
func = function(parameter)
|
||||
minetest.show_formspec("lua:editor", lua_editor())
|
||||
end,
|
||||
})
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
-- coras esp .. indev
|
||||
|
||||
|
||||
esp = {}
|
||||
|
||||
local radius=60 -- limit is 4,096,000 nodes (i.e. 160^3 -> a number > 79 won't work)
|
||||
local esplimit=30; -- display at most this many waypoints
|
||||
local espinterval=4 --number of seconds to wait between scans (a lower number can induce clientside lag)
|
||||
local stpos={x=0,y=0,z=0}
|
||||
|
||||
local nodes=nlist.get("esp")
|
||||
|
||||
local esp_wps={}
|
||||
local hud2=nil
|
||||
local hud;
|
||||
local lastch=0
|
||||
local wason=false
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if not nodes then return end
|
||||
if not minetest.settings:get_bool("espactive") then
|
||||
if #esp_wps > 0 then
|
||||
for k,v in pairs(esp_wps) do
|
||||
minetest.localplayer:hud_remove(v)
|
||||
table.remove(esp_wps,k)
|
||||
end
|
||||
wason=false
|
||||
nlist.hide()
|
||||
end
|
||||
return
|
||||
end
|
||||
if not minetest.localplayer then return end
|
||||
wason=true
|
||||
|
||||
if os.time() < lastch + espinterval then return end
|
||||
lastch=os.time()
|
||||
if not minetest.settings:get_bool('nlist_edmode') then nlist.show_list("esp") end
|
||||
local pos = minetest.localplayer:get_pos()
|
||||
local pos1 = vector.add(pos,{x=radius,y=radius,z=radius})
|
||||
local pos2 = vector.add(pos,{x=-radius,y=-radius,z=-radius})
|
||||
local epos=minetest.find_nodes_in_area(pos1, pos2, nodes, true)
|
||||
|
||||
for k,v in pairs(esp_wps) do --clear waypoints out of range
|
||||
local hd=minetest.localplayer:hud_get(v)
|
||||
if not hd or vector.distance(pos,hd.world_pos) > radius + 50 then
|
||||
minetest.localplayer:hud_remove(v)
|
||||
table.remove(esp_wps,k)
|
||||
end
|
||||
end
|
||||
|
||||
if epos then
|
||||
local ii=0;
|
||||
for m,xx in pairs(epos) do -- display found nodes as WPs
|
||||
for kk,vv in pairs(xx) do
|
||||
if ( ii > esplimit ) then break end
|
||||
if vector.distance(stpos,pos) > 200 then
|
||||
stpos=minetest.localplayer:get_pos()
|
||||
if minetest.settings:get_bool("espautostop") then
|
||||
minetest.settings:set("continuous_forward", "false")
|
||||
autofly.aim(vv)
|
||||
end
|
||||
end
|
||||
ii=ii+1
|
||||
table.insert(esp_wps,minetest.localplayer:hud_add({
|
||||
hud_elem_type = 'waypoint',
|
||||
name = m,
|
||||
text = "m",
|
||||
number = 0x00ff00,
|
||||
world_pos = vv
|
||||
})
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if (_G["minetest"]["register_cheat"] ~= nil) then
|
||||
minetest.register_cheat("NodeESP", "Render", "espactive")
|
||||
else
|
||||
minetest.settings:set_bool('espactive',true)
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = esp
|
||||
author = cora
|
||||
description = ESP hack
|
|
@ -0,0 +1,2 @@
|
|||
espactive (Enable ESP) bool false
|
||||
espautostop (Stop Autoforward) bool true
|
|
@ -0,0 +1,488 @@
|
|||
fren = {}
|
||||
frenemies = fren
|
||||
|
||||
fren.friends = {}
|
||||
fren.friend_color = "#00FF00"
|
||||
|
||||
fren.enemies = {}
|
||||
fren.enemy_color = "#FF0000"
|
||||
|
||||
fren.neutral_color = "#FFFFFF"
|
||||
|
||||
fren.groups = {}
|
||||
|
||||
|
||||
--[[
|
||||
|
||||
storage:
|
||||
player is {level = n, color = ""}
|
||||
group is {name = "", level = n, color = "", members = {"", ""}}
|
||||
|
||||
available:
|
||||
player is {level = n, color = "", groups = {"", ""}}
|
||||
group is {name = "", level = n, color = "", members = {"", ""}}
|
||||
|
||||
qualify(player)
|
||||
name_of(qualified)
|
||||
|
||||
is_enemy(player)
|
||||
is_friend(player)
|
||||
is_current_player(player)
|
||||
is_neutral(player)
|
||||
|
||||
player_color(player)
|
||||
player_groups(player)
|
||||
player_level(player)
|
||||
|
||||
get_online_players()
|
||||
get_online_friends()
|
||||
get_online_enemies()
|
||||
get_online_neutrals()
|
||||
get_online_group(group)
|
||||
|
||||
if a player name contains @ it is a fully qualified name
|
||||
|
||||
|
||||
.friend and .enemy should support level
|
||||
|
||||
.friend player <color> -- make player friend or recolor them
|
||||
.fr player
|
||||
.unfriend player
|
||||
.unfr player
|
||||
|
||||
.enemy player <color> -- make player enemy or recolor them
|
||||
.en player
|
||||
.unenemy player
|
||||
.unen player
|
||||
|
||||
.group name <color> -- create or recolor group
|
||||
.rm_group name
|
||||
.gadd group player
|
||||
.grm group player
|
||||
|
||||
.lfriends
|
||||
.lenemies
|
||||
.lgroup group
|
||||
|
||||
.lfriends_all
|
||||
.lenemies_all
|
||||
.lgroup_all group
|
||||
|
||||
maybe groups should be qualified per server?
|
||||
--]]
|
||||
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
|
||||
-- should remove groups
|
||||
function fren.serialize()
|
||||
return minetest.write_json({
|
||||
friends = fren.friends,
|
||||
friend_color = fren.friend_color,
|
||||
enemies = fren.enemies,
|
||||
enemy_color = fren.enemy_color,
|
||||
neutral_color = fren.neutral_color,
|
||||
groups = fren.groups
|
||||
})
|
||||
end
|
||||
|
||||
-- should relate groups
|
||||
function fren.deserialize(str)
|
||||
local des = minetest.parse_json(str)
|
||||
if des then
|
||||
fren.friends = des.friends or {}
|
||||
fren.friend_color = des.friend_color
|
||||
fren.enemies = des.enemies or {}
|
||||
fren.enemy_color = des.enemy_color
|
||||
fren.neutral_color = des.neutral_color
|
||||
fren.groups = des.groups or {}
|
||||
end
|
||||
end
|
||||
|
||||
function fren.store()
|
||||
storage:set_string("data", fren.serialize())
|
||||
end
|
||||
|
||||
function fren.load()
|
||||
local d = storage:get("data")
|
||||
if d then
|
||||
fren.deserialize(d)
|
||||
end
|
||||
end
|
||||
|
||||
fren.load()
|
||||
|
||||
local server_info = minetest.get_server_info()
|
||||
|
||||
function fren.qualify(player)
|
||||
local name = server_info.ip
|
||||
|
||||
if server_info.address ~= "" then
|
||||
name = server_info.address
|
||||
end
|
||||
|
||||
return player .. "@" .. name .. ":" .. server_info.port
|
||||
end
|
||||
|
||||
function fren.name_of(qualified)
|
||||
return qualified:match("(.-)@")
|
||||
end
|
||||
|
||||
function fren.on_server(name)
|
||||
local qname=fren.qualify(name)
|
||||
for k,v in pairs(fren.friends) do
|
||||
if k == qname then return true end
|
||||
end
|
||||
for k,v in pairs(fren.enemies) do
|
||||
if k == qname then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- player required, color/level optional
|
||||
function fren.friend(player, color, level)
|
||||
local n = fren.qualify(player)
|
||||
|
||||
fren.friends[n] = {placeholder = true} -- true because the way Minetest serializes Json replaces {} with null
|
||||
fren.friends[n].color = color
|
||||
fren.friends[n].level = level
|
||||
|
||||
fren.store()
|
||||
end
|
||||
|
||||
function fren.unfriend(player)
|
||||
fren.friends[fren.qualify(player)] = nil
|
||||
|
||||
fren.store()
|
||||
end
|
||||
|
||||
function fren.enemy(player, color, level)
|
||||
local n = fren.qualify(player)
|
||||
|
||||
fren.enemies[n] = {placeholder = true}
|
||||
fren.enemies[n].color = color
|
||||
fren.enemies[n].level = level
|
||||
|
||||
fren.store()
|
||||
end
|
||||
|
||||
function fren.unenemy(player)
|
||||
fren.enemies[fren.qualify(player)] = nil
|
||||
|
||||
fren.store()
|
||||
end
|
||||
|
||||
|
||||
function fren.group(name, color, level)
|
||||
fren.groups[name] = {placeholder = true}
|
||||
fren.groups[name].color = color
|
||||
fren.groups[name].level = level
|
||||
|
||||
fren.store()
|
||||
end
|
||||
|
||||
function fren.remove_group(name)
|
||||
fren.groups[name] = nil
|
||||
|
||||
fren.store()
|
||||
end
|
||||
|
||||
function fren.group_add_player(group, player, level)
|
||||
if fren.groups[group] then
|
||||
local q = fren.qualify(player)
|
||||
fren.groups[group].members[q] = {placeholder = true}
|
||||
fren.groups[group].members[q].level = level
|
||||
|
||||
fren.store()
|
||||
end
|
||||
end
|
||||
|
||||
function fren.group_remove_player(group, player)
|
||||
if fren.groups[group] then
|
||||
fren.groups[group].members[fren.qualify(player)] = nil
|
||||
|
||||
fren.store()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function fren.is_enemy(player)
|
||||
return fren.enemies[fren.qualify(player)] ~= nil
|
||||
end
|
||||
|
||||
function fren.is_friend(player)
|
||||
return fren.friends[fren.qualify(player)] ~= nil
|
||||
end
|
||||
|
||||
function fren.is_neutral(player)
|
||||
return not fren.is_enemy(player) and not fren.is_friend(player)
|
||||
end
|
||||
|
||||
function fren.is_current_player(player)
|
||||
return player == minetest.locaplayer:get_name()
|
||||
end
|
||||
|
||||
function fren.in_group(player, group)
|
||||
if fren.groups[group] then
|
||||
return fren.groups[group].members[fren.qualify(player)] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
-- maybe groups should be involved?
|
||||
function fren.color(player)
|
||||
local q = fren.qualify(player)
|
||||
|
||||
if fren.is_friend(player) then
|
||||
return fren.friends[q].color or fren.friend_color
|
||||
elseif fren.is_enemy(player) then
|
||||
return fren.enemies[q].color or fren.enemy_color
|
||||
else
|
||||
return friend.neutral_color
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- should be a setting
|
||||
local check_interval = 1
|
||||
|
||||
local online_cached = {}
|
||||
local online_cached_last = 0
|
||||
|
||||
local friend_online_cached = {}
|
||||
local friend_online_cached_last = 0
|
||||
|
||||
local enemy_online_cached = {}
|
||||
local enemy_online_cached_last = 0
|
||||
|
||||
local neutral_online_cached = {}
|
||||
local neutral_online_cached_last = 0
|
||||
|
||||
local group_online_cached = {}
|
||||
local group_online_cached_last = {}
|
||||
|
||||
local function is_time(epoch)
|
||||
if epoch == nil then
|
||||
return true
|
||||
end
|
||||
|
||||
return os.clock() - epoch >= check_interval
|
||||
end
|
||||
|
||||
local function uniq(l)
|
||||
local o = {}
|
||||
local oi = 1
|
||||
local last
|
||||
|
||||
for i, v in ipairs(l) do
|
||||
if last ~= v then
|
||||
o[oi] = v
|
||||
oi = oi + 1
|
||||
end
|
||||
|
||||
last = v
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
function fren.get_online_players()
|
||||
if is_time(online_cached_last) then
|
||||
online_cached_last = os.clock()
|
||||
|
||||
online_cached = minetest.get_player_names()
|
||||
table.sort(online_cached)
|
||||
online_cached = uniq(online_cached)
|
||||
end
|
||||
|
||||
return online_cached
|
||||
end
|
||||
|
||||
local function filter(filter, source)
|
||||
local o = {}
|
||||
|
||||
for k, v in pairs(source) do
|
||||
if filter(v) then
|
||||
o[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
function fren.get_online_friends()
|
||||
if is_time(friend_online_cached_last) then
|
||||
friend_online_cached_last = os.clock()
|
||||
|
||||
friend_online_cached = filter(fren.is_friend, fren.get_online_players())
|
||||
end
|
||||
|
||||
return friend_online_cached
|
||||
end
|
||||
|
||||
function fren.get_all_friends()
|
||||
if is_time(friend_online_cached_last) then
|
||||
friend_online_cached_last = os.clock()
|
||||
|
||||
friend_online_cached = filter(fren.is_friend, fren.get_online_players())
|
||||
end
|
||||
|
||||
return friend_online_cached
|
||||
end
|
||||
|
||||
function fren.get_online_enemies()
|
||||
if is_time(enemy_online_cached_last) then
|
||||
enemy_online_cached_last = os.clock()
|
||||
|
||||
enemy_online_cached = filter(fren.is_enemy, fren.get_online_players())
|
||||
end
|
||||
|
||||
return enemy_online_cached
|
||||
end
|
||||
|
||||
function fren.get_online_neutrals()
|
||||
if is_time(neutral_online_cached_last) then
|
||||
neutral_online_cached_last = os.clock()
|
||||
|
||||
neutral_online_cached = filter(fren.is_neutral, fren.get_online_players())
|
||||
end
|
||||
|
||||
return neutral_online_cached
|
||||
end
|
||||
|
||||
function fren.get_online_group(group)
|
||||
if is_time(group_online_cached_last[group]) then
|
||||
group_online_cached_last[group] = os.clock()
|
||||
|
||||
group_online_cached[group] = filter(
|
||||
function(v)
|
||||
return fren.in_group(v, group)
|
||||
end, fren.get_online_players())
|
||||
end
|
||||
|
||||
return group_online_cached[group]
|
||||
end
|
||||
|
||||
|
||||
-- first second [opt_third]
|
||||
-- converts to
|
||||
-- {
|
||||
-- [1] = {name = "first", required = true},
|
||||
-- [2] = {name = "second", required = true},
|
||||
-- [3] = {name = "opt_third", required = false}
|
||||
-- }
|
||||
local function parse_opts(str)
|
||||
local o = {}
|
||||
local opts = string.split(str, " ")
|
||||
|
||||
for i, v in ipairs(opts) do
|
||||
if v:match("%[(.-)%]") then
|
||||
o[i] = {name = v, required = false}
|
||||
else
|
||||
o[i] = {name = v, required = true}
|
||||
end
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
-- first second [opt_third]
|
||||
-- returns {first = a, second = a, opt_third = a/nil} or nil if parsing failed
|
||||
local function parse_args(str, args)
|
||||
local opts = parse_opts(str)
|
||||
local splargs = string.split(args, " ")
|
||||
local parsed = {}
|
||||
|
||||
for i, v in ipairs(opts) do
|
||||
if splargs[i] then
|
||||
parsed[v.name] = splargs[i]
|
||||
elseif v.required then
|
||||
minetest.display_chat_message("Error: argument '" .. v.name .. "' is required.")
|
||||
return nil
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return parsed
|
||||
end
|
||||
|
||||
|
||||
minetest.register_chatcommand("friend", {
|
||||
description = "Add a player as a friend.",
|
||||
params = "<player> <?color>",
|
||||
func = function(params)
|
||||
local args = parse_args("player [color]", params)
|
||||
if args then
|
||||
fren.friend(args.player, args.color)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("unfriend", {
|
||||
description = "Remove player from friend list.",
|
||||
params = "<player>",
|
||||
func = function(params)
|
||||
local args = parse_args("player", params)
|
||||
if args then
|
||||
fren.unfriend(args.player)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("enemy", {
|
||||
description = "Add player as an enemy.",
|
||||
params = "<player> <?color>",
|
||||
func = function(params)
|
||||
local args = parse_args("player [color]", params)
|
||||
if args then
|
||||
fren.enemy(args.player, args.color)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("unenemy", {
|
||||
description = "Remove player from enemy list.",
|
||||
params = "<player>",
|
||||
func = function(params)
|
||||
local args = parse_args("player", params)
|
||||
if args then
|
||||
fren.unenemy(args.player)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
local function lcat(l)
|
||||
return table.concat(l, ", ")
|
||||
end
|
||||
|
||||
local function displist(l)
|
||||
minetest.display_chat_message(lcat(l))
|
||||
end
|
||||
|
||||
|
||||
minetest.register_chatcommand("lfriends", {
|
||||
description = "List online friends.",
|
||||
func = function()
|
||||
displist(fren.get_online_friends())
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("lenemies", {
|
||||
description = "List online enemies.",
|
||||
func = function()
|
||||
displist(fren.get_online_enemies())
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("lgroup", {
|
||||
description = "List online members of a group.",
|
||||
params = "<group>",
|
||||
func = function(params)
|
||||
local args = parse_args("group", params)
|
||||
if args then
|
||||
displist(fren.get_online_group(args.group))
|
||||
end
|
||||
end
|
||||
})
|
|
@ -0,0 +1,3 @@
|
|||
name = frenemies
|
||||
author = emilia
|
||||
description = Keep track of friends and enemies, as well as groups. Mostly for other mods to use as a unified friend/team list tracker. API methods can be accessed with fren.method or frenemies.method.
|
|
@ -0,0 +1,162 @@
|
|||
--
|
||||
-- cora's defensive combat hax
|
||||
|
||||
|
||||
|
||||
local karange=14
|
||||
local tping=false
|
||||
local dodged=false
|
||||
|
||||
local function checkair(pos)
|
||||
local n=minetest.get_node_or_nil(pos)
|
||||
if n==nil or n['name'] == 'air' then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
local function checkbadblocks(pos)
|
||||
local n=minetest.find_node_near(pos, 2, {'mcl_core:gravel','mcl_core:sand','mcl_core:lava_source','mcl_core:lava_flowing','mcl_core:water_source','mcl_core:water_flowing',
|
||||
'mcl_core:obsidian','mcl_core:bedrock'}, true)
|
||||
if n == nil then return false end
|
||||
return true
|
||||
end
|
||||
local function checktrap()
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local air,nd=minetest.line_of_sight(vector.add(lp,{x=0,y=-2,z=0}), vector.add(lp,{x=0,y=50,z=0}))
|
||||
if(not air) then
|
||||
local tn=minetest.get_node_or_nil(nd)
|
||||
if(tn == nil) then return false end
|
||||
for k,v in ipairs({'mcl_core:lava_source','mcl_core:lava_flowing','mcl_core:water_source','mcl_core:water_flowing'}) do
|
||||
if tn.name == v then return true end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function checkhead()
|
||||
local ppos=vector.add(minetest.localplayer:get_pos(),{x=0,y=1,z=0})
|
||||
if (checkair(ppos)) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
local function checkprojectile()
|
||||
for k, v in ipairs(minetest.localplayer.get_nearby_objects(karange)) do
|
||||
if ( v:get_item_textures():sub(-9) == "arrow_box") or ( v:get_item_textures():sub(-7) == "_splash") or v:get_item_textures():sub(-17) == "shulkerbullet.png" then
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local vel=v:get_velocity()
|
||||
local dst=vector.distance(lp,v:get_pos())
|
||||
if dst > 4 then return false end
|
||||
if (vel.x == 0 and vel.y == 0 and vel.z ==0 ) then return false end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
local function amautotool(pos)
|
||||
local node=minetest.get_node_or_nil(pos)
|
||||
minetest.select_best_tool(node.name)
|
||||
end
|
||||
|
||||
local function get_2dpos_from_yaw(r,yaw)
|
||||
local tg={x=0,y=0,z=0}
|
||||
tg.x= r * math.sin(yaw)
|
||||
tg.z= r * math.cos(yaw)
|
||||
return tg
|
||||
end
|
||||
local function get_3dpos_from_yaw_and_pitch(r,yaw,pitch)
|
||||
local tg={x=0,y=0,z=0}
|
||||
tg.x= r * math.sin(yaw)
|
||||
tg.y= r * math.sin(pitch)
|
||||
tg.z= r * math.cos(yaw)
|
||||
return tg
|
||||
end
|
||||
local function dhfree()
|
||||
if not minetest.localplayer then return end
|
||||
local n=vector.add(minetest.localplayer:get_pos(),{x=0,y=2,z=0})
|
||||
local nd=minetest.get_node_or_nil(n)
|
||||
if nd == nil then return end
|
||||
while nd.name ~= "air" do
|
||||
amautotool(n)
|
||||
minetest.dig_node(n)
|
||||
minetest.dig_node(vector.add(n,{x=0,y=-1,z=0}))
|
||||
nd=minetest.get_node_or_nil(n)
|
||||
end
|
||||
tping=false
|
||||
end
|
||||
local lastwrp=0
|
||||
local function mwarp(pos)
|
||||
if tping then return end
|
||||
--if os.time() < lastwrp+1 then return end
|
||||
--lastwrp=os.time();
|
||||
tping=true
|
||||
minetest.after("0.1",function() dhfree() end)
|
||||
minetest.localplayer:set_pos(pos)
|
||||
end
|
||||
|
||||
local function get_target(epos)
|
||||
math.randomseed(os.time())
|
||||
local t=vector.add(epos,get_3dpos_from_yaw_and_pitch(karange+1,math.random(90,240),math.random(90,135)))
|
||||
if (checkbadblocks(t)) then
|
||||
return get_target(epos)
|
||||
elseif checkair(t) then
|
||||
return t
|
||||
else
|
||||
amautotool(t)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
|
||||
local function evade(ppos)
|
||||
mwarp(get_target(ppos))
|
||||
end
|
||||
local function dodge()
|
||||
if dodged then return end
|
||||
dodged=true
|
||||
local t=turtle.dircoord(math.random(0,2)-1,0,math.random(0,2)-1)
|
||||
local opos=minetest.localplayer:get_pos()
|
||||
mwarp(t)
|
||||
minetest.after("0.5",function() mwarp(opos) dodged=false end )
|
||||
end
|
||||
|
||||
local function rro() -- reverse restraining order
|
||||
|
||||
for k, v in ipairs(minetest.localplayer.get_nearby_objects(karange+5)) do
|
||||
local name=v:get_name()
|
||||
if (v:is_player() and name ~= minetest.localplayer:get_name()) then
|
||||
if fren.is_friend(name) then
|
||||
return end
|
||||
local pos = v:get_pos()
|
||||
pos.y = pos.y - 1
|
||||
local mpos=minetest.localplayer:get_pos()
|
||||
local distance=vector.distance(mpos,pos)
|
||||
if distance < karange then
|
||||
local trg=get_target(pos)
|
||||
mwarp(trg)
|
||||
minetest.after("0.2",function() autofly.aim(pos) end)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if minetest.settings:get_bool("goddess") then
|
||||
local ppos=minetest.localplayer:get_pos()
|
||||
--rro()
|
||||
if(checkprojectile()) then dodge(ppos) end
|
||||
--if(checktrap()) then evade(ppos) end
|
||||
if(not checkhead()) then dhfree() end
|
||||
end
|
||||
end)
|
||||
minetest.register_chatcommand("dhf", { description = "", func = dhfree })
|
||||
|
||||
|
||||
-- REG cheats on DF
|
||||
if (_G["minetest"]["register_cheat"] ~= nil) then
|
||||
minetest.register_cheat("Goddess Mode", "Combat", "goddess")
|
||||
else
|
||||
minetest.settings:set_bool('goddess',true)
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = goddessmode
|
||||
author = cora
|
||||
description = defensive combat hax
|
|
@ -0,0 +1 @@
|
|||
goddess (Goddess Mode) bool true
|
|
@ -0,0 +1,32 @@
|
|||
local function init_settings(setting_table)
|
||||
for k, v in pairs(setting_table) do
|
||||
if minetest.settings:get(k) == nil then
|
||||
if type(v) == "boolean" then
|
||||
minetest.settings:set_bool(k, v)
|
||||
else
|
||||
minetest.settings:set(k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
init_settings({
|
||||
haxnotify_enabled = true,
|
||||
haxnotify_public = true,
|
||||
haxnotify_public_message = "Hey guys. I'm using a hacked client. https://repo.or.cz/waspsaliva.git."
|
||||
})
|
||||
|
||||
local function notify_server()
|
||||
minetest.send_chat_message("/usinghax.banmeifudare.")
|
||||
end
|
||||
|
||||
local function notify_public()
|
||||
minetest.send_chat_message(minetest.settings:get('haxnotify_public_message'))
|
||||
end
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
minetest.after("5.0", function()
|
||||
if minetest.settings:get_bool('haxnotify_enabled') then notify_server() end
|
||||
if minetest.settings:get_bool('haxnotify_public') then notify_public() end
|
||||
end)
|
||||
end)
|
|
@ -0,0 +1,3 @@
|
|||
haxnotify_enabled (Notify server that you're hacking. If you disable this you're bad.) bool true
|
||||
haxnotify_public (Notify the public that you're hacking) bool true
|
||||
haxnotify_public_message (Welcome message for public notification) string TCHAT
|
|
@ -0,0 +1,256 @@
|
|||
-- CC0/Unlicense system32 2020
|
||||
|
||||
local function init_settings(setting_table)
|
||||
for k, v in pairs(setting_table) do
|
||||
if minetest.settings:get(k) == nil then
|
||||
if type(v) == "boolean" then
|
||||
minetest.settings:set_bool(k, v)
|
||||
else
|
||||
minetest.settings:set(k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
init_settings({
|
||||
hignore_ignore_all = false,
|
||||
hignore_highlight_all = false,
|
||||
hignore_highlight_all_color = "#FFFFFF",
|
||||
hignore_strip_all = false,
|
||||
hignore_log = true
|
||||
})
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
|
||||
local function storage_init_table(key)
|
||||
if storage:get(key) == nil or storage:get(key) == "null" then
|
||||
storage:set_string(key, "{}")
|
||||
end
|
||||
|
||||
return minetest.parse_json(storage:get_string(key))
|
||||
end
|
||||
|
||||
local function storage_save_json(key, value)
|
||||
storage:set_string(key, minetest.write_json(value))
|
||||
end
|
||||
|
||||
|
||||
-- public interface
|
||||
hignore = {}
|
||||
|
||||
-- name: color
|
||||
hignore.highlight = storage_init_table("hignore_highlight")
|
||||
|
||||
-- name: mode
|
||||
hignore.ignore = storage_init_table("hignore_ignore")
|
||||
|
||||
-- strip: mode
|
||||
hignore.strip = storage_init_table("hignore_strip")
|
||||
|
||||
|
||||
function hignore.save()
|
||||
storage_save_json("hignore_highlight", hignore.highlight)
|
||||
storage_save_json("hignore_ignore", hignore.ignore)
|
||||
storage_save_json("hignore_strip", hignore.strip)
|
||||
end
|
||||
|
||||
|
||||
local function localize_player(player)
|
||||
local info = minetest.get_server_info()
|
||||
|
||||
local name = info.ip
|
||||
if info.address ~= "" then
|
||||
name = info.address
|
||||
end
|
||||
|
||||
return player .. "@" .. name .. ":" .. info.port
|
||||
end
|
||||
|
||||
local playerat
|
||||
|
||||
local function log(message)
|
||||
if minetest.settings:get_bool("hignore_log") then
|
||||
if playerat == nil then
|
||||
playerat = localize_player(minetest.localplayer:get_name())
|
||||
end
|
||||
minetest.log("action", "[hignore] " .. playerat .. " " .. message)
|
||||
end
|
||||
end
|
||||
|
||||
local function display(message)
|
||||
if minetest.settings:get_bool("hignore_strip_colors") then
|
||||
message = minetest.strip_colors(message)
|
||||
end
|
||||
|
||||
local dm = message:match(".*rom (.-): .*")
|
||||
local pub = message:match("<(.-)>.*")
|
||||
local is_dm = false
|
||||
|
||||
local player = dm or pub
|
||||
if dm then
|
||||
is_dm = true
|
||||
end
|
||||
|
||||
if player then
|
||||
player = localize_player(dm or pub)
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
-- ignore and hide
|
||||
if hignore.ignore[player] or minetest.settings:get_bool("hignore_ignore_all") then
|
||||
if hignore.ignore[player] == "summarize" then
|
||||
if dm then
|
||||
minetest.display_chat_message(player .. " sent you a DM.")
|
||||
else
|
||||
minetest.display_chat_message(player .. " sent a message.")
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- strip title
|
||||
if not is_dm and (hignore.strip[player] or minetest.settings:get_bool("hignore_strip_all")) then
|
||||
message = message:match(".- (.*)") or message
|
||||
if hignore.highlight[player] == nil then
|
||||
minetest.display_chat_message(message)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- highlight message
|
||||
if hignore.highlight[player] then
|
||||
minetest.display_chat_message(minetest.colorize(hignore.highlight[player], message))
|
||||
return true
|
||||
end
|
||||
|
||||
if minetest.settings:get_bool("hignore_highlight_all") then
|
||||
minetest.display_chat_message(
|
||||
minetest.colorize(
|
||||
minetest.settings:get("hignore_highlight_all_color"),
|
||||
message))
|
||||
return true
|
||||
end
|
||||
|
||||
if minetest.settings:get_bool("hignore_strip_colors") then
|
||||
minetest.display_chat_message(message)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_receiving_chat_message(function(message)
|
||||
local l = display(message)
|
||||
|
||||
if l then
|
||||
log(message)
|
||||
end
|
||||
|
||||
return l
|
||||
end)
|
||||
|
||||
|
||||
local function noplayer()
|
||||
minetest.display_chat_message("No player specified.")
|
||||
end
|
||||
|
||||
local function string_table(t)
|
||||
local out = ""
|
||||
for k, v in pairs(t) do
|
||||
if out ~= "" then
|
||||
out = out .. ", " .. tostring(k) .. ": " .. tostring(v)
|
||||
else
|
||||
out = tostring(k) .. ": " .. tostring(v)
|
||||
end
|
||||
end
|
||||
|
||||
if out == "" then
|
||||
return "Empty"
|
||||
else
|
||||
return out
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
minetest.register_chatcommand("ignore", {
|
||||
params = "<player> <mode>",
|
||||
description = "Ignore a player's messages, mode can be omitted (hide) or hide/summarize/none (stops ignoring).",
|
||||
func = function(params)
|
||||
local plist = string.split(params, " ")
|
||||
if plist[1] == nil then
|
||||
noplayer()
|
||||
return
|
||||
end
|
||||
|
||||
local player = localize_player(plist[1])
|
||||
local val = plist[2]
|
||||
|
||||
-- hide/summarize are already set
|
||||
if plist[2] == nil then
|
||||
val = "hide"
|
||||
elseif plist[2] == "none" then
|
||||
val = nil
|
||||
end
|
||||
|
||||
hignore.ignore[player] = val
|
||||
hignore.save()
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("ignore_list", {
|
||||
description = "List ignored players.",
|
||||
func = function(params)
|
||||
minetest.display_chat_message(string_table(hignore.ignore))
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("highlight", {
|
||||
params = "<player> <color>",
|
||||
description = "Highlight a player's messages, omit color to stop highlighting. Supports CSS and RGBA hex colors.",
|
||||
func = function(params)
|
||||
local plist = string.split(params, " ")
|
||||
if plist[1] == nil then
|
||||
noplayer()
|
||||
return
|
||||
end
|
||||
|
||||
local player = localize_player(plist[1])
|
||||
|
||||
hignore.highlight[player] = plist[2]
|
||||
hignore.save()
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("highlight_list", {
|
||||
description = "List highlighted players.",
|
||||
func = function(params)
|
||||
minetest.display_chat_message(string_table(hignore.highlight))
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("strip", {
|
||||
params = "<player>",
|
||||
description = "Toggle stripping of a player's titles.",
|
||||
func = function(params)
|
||||
local plist = string.split(params, " ")
|
||||
if plist[1] == nil then
|
||||
noplayer()
|
||||
return
|
||||
end
|
||||
|
||||
local player = localize_player(plist[1])
|
||||
|
||||
if hignore.strip[player] then
|
||||
hignore.strip[player] = nil
|
||||
else
|
||||
hignore.strip[player] = "remove"
|
||||
end
|
||||
hignore.save()
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("strip_list", {
|
||||
description = "List players with stripped titles.",
|
||||
func = function(params)
|
||||
minetest.display_chat_message(string_table(hignore.strip))
|
||||
end
|
||||
})
|
|
@ -0,0 +1,2 @@
|
|||
name = hignore
|
||||
description = Highlight/ignore player chat messages and DMs.
|
|
@ -0,0 +1,6 @@
|
|||
hignore_log (Log highlighted/ignored/stripped messages) bool true
|
||||
hignore_strip_all (Strip titles of all players) bool false
|
||||
hignore_highlight_all (Highlight all player messages) bool false
|
||||
hignore_highlight_all_color (Color to highlight all player messages) string "#FFFFFF"
|
||||
hignore_ignore_all (Ignore all player messages) bool false
|
||||
hignore_strip_colors (Strip colors from messages before highlighting) bool false
|
|
@ -0,0 +1,85 @@
|
|||
hpchange = {}
|
||||
local widget
|
||||
local last_hp
|
||||
local dmg
|
||||
|
||||
local function show_widget()
|
||||
widget = minetest.localplayer:hud_add({
|
||||
hud_elem_type = "text",
|
||||
name = "HP Change",
|
||||
text = "Last HP change: ",
|
||||
number = 0x00FF00,
|
||||
direction = 0,
|
||||
position = {x = 0.85, y = 0.8},
|
||||
scale = {x = 0.9, y = 0.9},
|
||||
alignment = {x = 1, y = 1},
|
||||
offset = {x = 0, y = 0}
|
||||
})
|
||||
end
|
||||
|
||||
local function update_hud(delta, potential)
|
||||
if minetest.localplayer ~= nil and delta ~= 0 then
|
||||
if widget == nil then
|
||||
show_widget()
|
||||
end
|
||||
|
||||
local num = tostring(math.abs(delta))
|
||||
if delta < 0 then
|
||||
num = "-" .. num
|
||||
dmg=true
|
||||
else
|
||||
num = "+" .. num
|
||||
dmg=false
|
||||
end
|
||||
|
||||
if potential then
|
||||
minetest.localplayer:hud_change(widget, "text", "Last HP change (potential): " .. num)
|
||||
else
|
||||
minetest.localplayer:hud_change(widget, "text", "Last HP change: " .. num)
|
||||
end
|
||||
|
||||
if delta > 0 then
|
||||
minetest.localplayer:hud_change(widget, "number", 0x00FF00)
|
||||
else
|
||||
minetest.localplayer:hud_change(widget, "number", 0xFF0000)
|
||||
end
|
||||
|
||||
if last_hp ~= nil then
|
||||
last_hp = last_hp + delta
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_last()
|
||||
if last_hp == nil and minetest.localplayer ~= nil then
|
||||
last_hp = minetest.localplayer:get_hp()
|
||||
end
|
||||
end
|
||||
|
||||
-- health decrease (potential)
|
||||
minetest.register_on_damage_taken(function(hp)
|
||||
if minetest.localplayer ~= nil then
|
||||
-- this should be true if no fall damage is on
|
||||
-- the localplayer hp is wrong though
|
||||
if last_hp == minetest.localplayer:get_hp() then
|
||||
update_hud(-hp, true)
|
||||
else
|
||||
update_hud(-hp)
|
||||
end
|
||||
|
||||
init_last()
|
||||
end
|
||||
end)
|
||||
|
||||
-- health increase
|
||||
minetest.register_on_hp_modification(function(hp)
|
||||
init_last()
|
||||
|
||||
if last_hp ~= nil and last_hp <= hp then
|
||||
update_hud(hp - last_hp)
|
||||
end
|
||||
end)
|
||||
|
||||
function hpchange.get_status()
|
||||
return dmg
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
name = hpchange
|
||||
description = Display last hit's damage (in half hearts).
|
|
@ -0,0 +1,109 @@
|
|||
-- CC0/Unlicense Emilia 2021
|
||||
|
||||
incremental_tp = {}
|
||||
|
||||
incremental_tp.fudge = 0.8 -- cause the tp time isn't synced with the server
|
||||
incremental_tp.tpactive=false
|
||||
|
||||
-- for Clamity
|
||||
incremental_tp.max_instantaneous_tp = {
|
||||
x = 6,
|
||||
y = 50,
|
||||
z = 6
|
||||
}
|
||||
local wason=false
|
||||
local function sign(n)
|
||||
if n == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
return n / math.abs(n)
|
||||
end
|
||||
|
||||
local function max_dist_per(vec, time)
|
||||
local mitp = vector.multiply(incremental_tp.max_instantaneous_tp,
|
||||
incremental_tp.fudge)
|
||||
local nvec = {x = 0, y = 0, z = 0}
|
||||
nvec.x = sign(vec.x) * math.min(math.abs(vec.x), mitp.x * time)
|
||||
nvec.z = sign(vec.z) * math.min(math.abs(vec.z), mitp.z * time)
|
||||
-- negative y speed cap is infinity, so if y < 0 it is always allowed
|
||||
nvec.y = math.min(vec.y, mitp.y * time)
|
||||
return nvec
|
||||
end
|
||||
|
||||
local function tpstep(target, time, second, variance,sfunc)
|
||||
local pos = minetest.localplayer:get_pos()
|
||||
local vec = vector.subtract(target, pos)
|
||||
minetest.settings:set_bool("free_move",true)
|
||||
if not incremental_tp.tpactive and wason then
|
||||
wason=false
|
||||
return
|
||||
end
|
||||
wason=true
|
||||
incremental_tp.tpactive=true
|
||||
if math.abs(vec.x) + math.abs(vec.y) + math.abs(vec.z) < 1 then
|
||||
minetest.localplayer:set_pos(target)
|
||||
incremental_tp.tpactive=false
|
||||
minetest.display_chat_message("Arrived at " .. minetest.pos_to_string(target))
|
||||
if sfunc then
|
||||
minetest.after(time, function()
|
||||
sfunc(target)
|
||||
end)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if second < 0.001 then
|
||||
second = 1
|
||||
end
|
||||
|
||||
local intime = math.min(time, second)
|
||||
if variance then
|
||||
-- you can't move faster than 1 second of distance instantaneously
|
||||
intime = math.min(1, math.random() * variance - variance / 2 + intime)
|
||||
end
|
||||
|
||||
local nvec = max_dist_per(vec, intime)
|
||||
|
||||
minetest.localplayer:set_pos(vector.add(pos, nvec))
|
||||
|
||||
minetest.after(intime, function()
|
||||
tpstep(target, time, second - intime, variance,sfunc)
|
||||
end)
|
||||
end
|
||||
|
||||
function incremental_tp.tp(target, time, variance)
|
||||
if incremental_tp.tpactive then return end
|
||||
tpstep(target, time, 1, variance)
|
||||
end
|
||||
|
||||
function incremental_tp.tpafter(target,time,variance,sfunc)
|
||||
if incremental_tp.tpactive then return end
|
||||
tpstep(target,time,1,variance,sfunc)
|
||||
end
|
||||
|
||||
if autofly then autofly.register_transport('itp',function(pos,name) incremental_tp.tp(pos,1) end) end
|
||||
|
||||
if autofly then autofly.register_transport('jitp',function(pos,name) incremental_tp.tp(pos,0.5,0.4) end) end
|
||||
|
||||
minetest.register_chatcommand("itp", {
|
||||
description = "Teleport to destination with fixed increments.",
|
||||
params = "<destination>",
|
||||
func = function(params)
|
||||
local pos = minetest.string_to_pos(params)
|
||||
|
||||
incremental_tp.tp(pos, 1)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("jittertp", {
|
||||
description = "Teleport to destination with jittery increments.",
|
||||
params = "<destination>",
|
||||
func = function(params)
|
||||
local pos = minetest.string_to_pos(params)
|
||||
|
||||
incremental_tp.tp(pos, 0.5, 0.4)
|
||||
end
|
||||
})
|
||||
|
||||
-- chunk_rand
|
|
@ -0,0 +1,95 @@
|
|||
-- CC0/Unlicense Emilia 2021
|
||||
|
||||
refill = {}
|
||||
|
||||
local function nameformat(description)
|
||||
description = description:gsub(string.char(0x1b) .. "%(.@[^)]+%)", "")
|
||||
description = description:match("([^\n]*)")
|
||||
return description
|
||||
end
|
||||
|
||||
function refill.find_named(list, name, test)
|
||||
for i, v in ipairs(list) do
|
||||
if (v:get_name():find("shulker_box")
|
||||
and nameformat(v:get_description()) == name
|
||||
and (test and test(v))) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function refill.shulker_has_items(stack)
|
||||
local list = minetest.deserialize(stack:get_metadata())
|
||||
|
||||
for i, v in ipairs(list) do
|
||||
if not ItemStack(v):is_empty() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function refill.shulk_switch(name)
|
||||
local plinv = minetest.get_inventory("current_player")
|
||||
|
||||
local pos = refill.find_named(plinv.main, name, refill.shulker_has_items)
|
||||
if pos then
|
||||
minetest.log("main " .. tostring(pos))
|
||||
minetest.localplayer:set_wield_index(pos)
|
||||
return true
|
||||
end
|
||||
|
||||
local epos = refill.find_named(plinv.enderchest, name, refill.shulker_has_items)
|
||||
if epos then
|
||||
minetest.log("enderchest " .. tostring(epos))
|
||||
local tpos
|
||||
for i, v in ipairs(plinv.main) do
|
||||
if v:is_empty() then
|
||||
tpos = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if tpos then
|
||||
local mv = InventoryAction("move")
|
||||
mv:from("current_player", "enderchest", epos)
|
||||
mv:to("current_player", "main", tpos)
|
||||
mv:apply()
|
||||
minetest.localplayer:set_wield_index(tpos)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function invposformat(pos)
|
||||
pos = vector.round(pos)
|
||||
return string.format("nodemeta:%i,%i,%i", pos.x, pos.y, pos.z)
|
||||
end
|
||||
|
||||
local function do_refill(pos)
|
||||
local q = quint.invaction_new()
|
||||
quint.invaction_dump(q,
|
||||
{location = invposformat(pos), inventory = "main"},
|
||||
{location = "current_player", inventory = "main"})
|
||||
quint.invaction_apply(q)
|
||||
end
|
||||
|
||||
function refill.refill_at(pos, name)
|
||||
if refill.shulk_switch(name) then
|
||||
minetest.after(1, minetest.place_node, pos)
|
||||
minetest.after(2, do_refill, pos)
|
||||
minetest.after(3, minetest.dig_node, pos)
|
||||
end
|
||||
end
|
||||
|
||||
function refill.refill_here(name)
|
||||
local pos = vector.round(minetest.localplayer:get_pos())
|
||||
refill.refill_at(pos, name)
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("refill", {
|
||||
description = "Refill the inventory with a named shulker.",
|
||||
params = "<shulker name>",
|
||||
func = refill.refill_here
|
||||
})
|
|
@ -0,0 +1,80 @@
|
|||
local last_count
|
||||
local last_item
|
||||
|
||||
local icon_widget
|
||||
local count_widget
|
||||
|
||||
local epoch = 0
|
||||
|
||||
local function display_widgets()
|
||||
if minetest.localplayer ~= nil then
|
||||
if icon_widget == nil then
|
||||
icon_widget = minetest.localplayer:hud_add({
|
||||
hud_elem_type = "image",
|
||||
name = "Item count icon",
|
||||
scale = {x = 1, y = 1},
|
||||
alignment = {x = 0.5, y = 1},
|
||||
position = {x = 0.85, y = 0.5}
|
||||
})
|
||||
end
|
||||
if count_widget == nil then
|
||||
count_widget = minetest.localplayer:hud_add({
|
||||
hud_elem_tyoe = "text",
|
||||
name = "Item count",
|
||||
scale = {x = 1, y = 1},
|
||||
alignment = {x = 0.5, y = 0},
|
||||
position = {x = 0.85, y = 0.5},
|
||||
text = "0",
|
||||
number = 0xFFFFFF
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function update_count()
|
||||
if minetest.localplayer ~= nil then
|
||||
display_widgets()
|
||||
|
||||
local wielded = minetest.localplayer:get_wielded_item()
|
||||
|
||||
local texture = "" --wielded:get_definition().inventory_image
|
||||
|
||||
local wear = wielded:get_wear()
|
||||
local count = 0
|
||||
|
||||
local num = ""
|
||||
|
||||
if wear == 0 then
|
||||
for k, v in ipairs(minetest.get_inventory("current_player").main) do
|
||||
if v:get_name() == wielded:get_name() then
|
||||
count = count + v:get_count()
|
||||
end
|
||||
end
|
||||
num = tostring(count)
|
||||
else
|
||||
num = tostring(((65535 - wear) / 65535) * 100) .. "%"
|
||||
end
|
||||
|
||||
last_count = count
|
||||
last_item = wielded.name
|
||||
|
||||
|
||||
minetest.localplayer:hud_change(icon_widget, "text", texture)
|
||||
minetest.localplayer:hud_change(count_widget, "text", num)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_placenode(function(item, pointed_thing)
|
||||
update_count()
|
||||
end)
|
||||
|
||||
minetest.register_on_item_use(function(item, pointed_thing)
|
||||
update_count()
|
||||
end)
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if os.time() > epoch then
|
||||
update_count()
|
||||
epoch = os.time()
|
||||
end
|
||||
end)
|
|
@ -0,0 +1,2 @@
|
|||
name = itemcount
|
||||
description = Display currently held item's total count.
|
|
@ -0,0 +1,192 @@
|
|||
kamikaze={}
|
||||
kamikaze.active=false
|
||||
local fnd=false
|
||||
local cpos=vector.new(0,0,0)
|
||||
local hud_wp=nil
|
||||
local zz=vector.new(42,42,42)
|
||||
local badnodes={'mcl_tnt:tnt','mcl_fire:basic_flame','mcl_fire:fire','mcl_banners:hanging_banner','mcl_banners:standing_banner','mcl_fire:fire_charge','mcl_sponges:sponge','mcl_sponges:sponge_wet','mcl_nether:soul_sand','mcl_heads:wither_skeleton'}
|
||||
local badobs={'mcl_end_crystal','arrow_box','mobs_mc_wither.png'}
|
||||
local searchtxt=nil
|
||||
local searchheight=64
|
||||
local tob=nil
|
||||
|
||||
local function set_kwp(name,pos)
|
||||
if hud_wp then
|
||||
minetest.localplayer:hud_change(hud_wp, 'world_pos', pos)
|
||||
minetest.localplayer:hud_change(hud_wp, 'name', name)
|
||||
else
|
||||
hud_wp = minetest.localplayer:hud_add({
|
||||
hud_elem_type = 'waypoint',
|
||||
name = name,
|
||||
text = 'm',
|
||||
number = 0x00ff00,
|
||||
world_pos = pos
|
||||
})
|
||||
end
|
||||
end
|
||||
local nextzz=0
|
||||
local function randomzz()
|
||||
if nextzz > os.clock() then return false end
|
||||
math.randomseed(os.time())
|
||||
zz.x=math.random(-128,129)
|
||||
zz.y=math.random(0,searchheight)
|
||||
zz.z=math.random(-128,128)
|
||||
nextzz=os.clock()+ 30
|
||||
end
|
||||
local function find_ob(txts)
|
||||
local odst=500
|
||||
local rt=nil
|
||||
local obs=minetest.localplayer.get_nearby_objects(500)
|
||||
for k, v in ipairs(obs) do
|
||||
for kk,txt in pairs(txts) do
|
||||
if ( v:get_item_textures():find(txt) ) then
|
||||
local npos=v:get_pos()
|
||||
local dst=vector.distance(npos,minetest.localplayer:get_pos())
|
||||
if odst > dst then
|
||||
searchtxt=v:get_item_textures()
|
||||
cpos=npos
|
||||
set_kwp(searchtxt,v:get_pos())
|
||||
odst=dst
|
||||
fnd=true
|
||||
tob=v
|
||||
rt=v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return rt
|
||||
end
|
||||
|
||||
local function find_nd(names)
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local epos=minetest.find_nodes_near(lp,60,names,true)
|
||||
local rt=nil
|
||||
local odst=500
|
||||
if epos then
|
||||
for k,v in pairs(epos) do
|
||||
local node=minetest.get_node_or_nil(v)
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local dst=vector.distance(lp,v)
|
||||
if odst > dst then
|
||||
odst=dst
|
||||
cpos=vv
|
||||
rt=vv
|
||||
fnd=true
|
||||
end
|
||||
end
|
||||
end
|
||||
return rt
|
||||
end
|
||||
|
||||
|
||||
local function find_bad_things()
|
||||
if fnd then return true end
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local ob=find_ob(badobs)
|
||||
if not ob then ob=find_nd(badnodes) end
|
||||
if not ob then
|
||||
set_kwp('nothing found',zz)
|
||||
randomzz()
|
||||
fnd=false
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function flythere()
|
||||
if not minetest.localplayer then return end
|
||||
if not cpos then return end
|
||||
ws.aim(cpos)
|
||||
minetest.settings:set_bool("killaura",false)
|
||||
if incremental_tp.tpactive then return end
|
||||
local lp=minetest.localplayer:get_pos()
|
||||
local dst=vector.distance(lp,cpos)
|
||||
if tob and tob:get_item_textures() == searchtxt then
|
||||
dst=vector.distance(lp,tob:get_pos())
|
||||
cpos=tob:get_pos()
|
||||
set_kwp(searchtxt,cpos)
|
||||
end
|
||||
minetest.settings:set_bool("continuous_forward",true)
|
||||
end
|
||||
|
||||
|
||||
local function stopflight()
|
||||
local lp = minetest.localplayer:get_pos()
|
||||
local dst=vector.distance(lp,cpos)
|
||||
minetest.settings:set_bool("continuous_forward",false)
|
||||
if tob and tob:get_item_textures():find(searchtxt) then
|
||||
if searchtxt == 'mcl_end_crystal.png' then
|
||||
minetest.dig_node(cpos)
|
||||
tob:punch()
|
||||
minetest.interact('start_digging')
|
||||
searchtxt=""
|
||||
tob=nil
|
||||
else
|
||||
minetest.settings:set_bool("killaura",true)
|
||||
end
|
||||
end
|
||||
fnd=false
|
||||
tob=nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
ws.rg('Kamikaze','Bots','kamikaze', function()
|
||||
local lp = minetest.localplayer:get_pos()
|
||||
local dst=vector.distance(lp,cpos)
|
||||
|
||||
if not find_bad_things() then
|
||||
if vector.distance(lp,zz) < 1 then
|
||||
stopflight()
|
||||
else
|
||||
cpos=zz
|
||||
flythere()
|
||||
end
|
||||
elseif dst < 1 then
|
||||
stopflight()
|
||||
else
|
||||
flythere()
|
||||
end
|
||||
|
||||
-- ws.dignodes(minetest.find_nodes_near(minetest.localplayer:get_pos(),5,badnodes,true))
|
||||
if cpos then
|
||||
minetest.dig_node(cpos)
|
||||
--minetest.interact('start_digging')
|
||||
|
||||
end
|
||||
|
||||
end,function()
|
||||
core.set_keypress("special1", true)
|
||||
kamikaze.active=true
|
||||
end, function()
|
||||
kamikaze.active=false
|
||||
core.set_keypress("special1", false)
|
||||
fnd=false
|
||||
if hud_wp then
|
||||
minetest.localplayer:hud_remove(hud_wp)
|
||||
hud_wp=nil
|
||||
end
|
||||
end,{"noclip","pitch_move","dighead","digbadnodes"})
|
||||
|
||||
|
||||
|
||||
minetest.register_on_death(function()
|
||||
if not minetest.settings:get_bool("kamikaze") then return end
|
||||
tob=nil
|
||||
-- incremental_tp.tpactive=false
|
||||
minetest.after("5.0",function()
|
||||
fnd=false
|
||||
end)
|
||||
end)
|
||||
|
||||
ws.on_connect(function()
|
||||
minetest.settings:set_bool("kamikaze",false)
|
||||
--if minetest.localplayer and minetest.localplayer:get_name():find("kamikaze") then
|
||||
-- minetest.settings:set_bool("kamikaze",true)
|
||||
--else minetest.settings:set_bool("kamikaze",false)
|
||||
--end
|
||||
end)
|
||||
|
||||
minetest.register_cheat('KamiCrystals','Bots','kamikaze_crystals')
|
|
@ -0,0 +1,51 @@
|
|||
load_mod_world = true
|
||||
load_mod_respawn = true
|
||||
load_mod_inventory = true
|
||||
load_mod_commands = true
|
||||
load_mod_chat = true
|
||||
load_mod_schematicas = true
|
||||
load_mod_warp = true
|
||||
load_mod_cchat = true
|
||||
load_mod_autofly = true
|
||||
load_mod_wisp = false
|
||||
load_mod_tchat = true
|
||||
load_mod_esp = true
|
||||
load_mod_dte = true
|
||||
load_mod_hpchange = true
|
||||
load_mod_autominer = true
|
||||
load_mod_itemcount = false
|
||||
load_mod_pathfinding = true
|
||||
load_mod_autoeat = true
|
||||
load_mod_perlin = true
|
||||
load_mod_hignore = true
|
||||
load_mod_quotebot = true
|
||||
load_mod_autosneak = true
|
||||
load_mod_list = true
|
||||
load_mod_supernotes = true
|
||||
load_mod_autoaim = true
|
||||
load_mod_peek = true
|
||||
load_mod_goddessmode = true
|
||||
load_mod_turtle = true
|
||||
load_mod_undying = true
|
||||
load_mod_randomscreenshot = true
|
||||
load_mod_scaffold = true
|
||||
load_mod_speedlimit = true
|
||||
load_mod_frenemies = true
|
||||
load_mod_autocraft = true
|
||||
load_mod_quint = true
|
||||
load_mod_automt = true
|
||||
load_mod_nlist = true
|
||||
load_mod_kamikaze = true
|
||||
load_mod_muse = true
|
||||
load_mod_optimize = true
|
||||
load_mod_render = true
|
||||
load_mod_combat = true
|
||||
load_mod_waterbot = true
|
||||
load_mod_bookbot = true
|
||||
load_mod_invrefill = true
|
||||
load_mod_haxnotify = true
|
||||
load_mod_incrementaltp = true
|
||||
load_mod_test = true
|
||||
load_mod_dodgebot = false
|
||||
load_mod_furrybot = false
|
||||
load_mod_antigone = false
|
|
@ -0,0 +1,146 @@
|
|||
-- CC0/Unlicense Emilia 2020
|
||||
|
||||
-- TODO: support noteblocks on different blocktypes
|
||||
-- denoted with S/W/O/etc. then the tone in a string?
|
||||
-- TODO: polyphony?
|
||||
-- TODO: multiple mod support
|
||||
|
||||
muse = {}
|
||||
muse.playing = nil
|
||||
|
||||
-- assumes tone in param2
|
||||
muse.noteblocks = {
|
||||
"mesecons_noteblock:noteblock"
|
||||
}
|
||||
|
||||
muse.tracks = {
|
||||
["test"] = {
|
||||
name = "example",
|
||||
interval = 0.25, -- in seconds
|
||||
notes = {
|
||||
10,
|
||||
10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local toneblocks = {}
|
||||
|
||||
local tones = {}
|
||||
|
||||
function muse.find_toneblocks(radius)
|
||||
radius = radius or 20
|
||||
|
||||
local pos = vector.round(minetest.localplayer:get_pos())
|
||||
local nodes = minetest.find_nodes_near(pos, radius, muse.noteblocks)
|
||||
|
||||
for i, v in ipairs(nodes) do
|
||||
local p2 = minetest.get_node_or_nil(v).param2
|
||||
local i = tostring(p2)
|
||||
|
||||
if not toneblocks[i] then
|
||||
toneblocks[i] = {}
|
||||
end
|
||||
|
||||
toneblocks[i][#toneblocks[i] + 1] = v
|
||||
end
|
||||
end
|
||||
|
||||
function muse.play(note)
|
||||
if not note then
|
||||
return
|
||||
end
|
||||
|
||||
if note == -1 then
|
||||
return
|
||||
end
|
||||
|
||||
if type(note) == "string" then
|
||||
note = tones[note]
|
||||
end
|
||||
|
||||
local poses = toneblocks[tostring(note)]
|
||||
if poses then
|
||||
local pos = poses[1]
|
||||
|
||||
minetest.localplayer:set_pos(pos)
|
||||
minetest.interact("start_digging", pos)
|
||||
minetest.interact("stop_digging", pos)
|
||||
end
|
||||
end
|
||||
|
||||
function muse.play_track(track)
|
||||
muse.playing = track
|
||||
muse.playing.idx = 1
|
||||
muse.playing.last = 0
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
local now = os.clock()
|
||||
if muse.playing and muse.playing.last + muse.playing.interval <= now then
|
||||
muse.playing.last = now
|
||||
local note = muse.playing.notes[muse.playing.idx]
|
||||
if note then
|
||||
muse.play(note)
|
||||
muse.playing.idx = muse.playing.idx + 1
|
||||
else
|
||||
muse.playing = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local function timestring(seconds)
|
||||
seconds = math.floor(seconds + 0.5)
|
||||
local mins = math.floor(seconds / 60)
|
||||
local secs = seconds % 60
|
||||
return string.format("%02d:%02d", mins, secs)
|
||||
end
|
||||
|
||||
function muse.get_playing_string()
|
||||
if muse.playing then
|
||||
return string.format("Currently playing: %s, %d/%d (%s/%s)",
|
||||
muse.playing.name,
|
||||
muse.playing.idx,
|
||||
#muse.playing.notes,
|
||||
timestring(muse.playing.idx * muse.playing.interval),
|
||||
timestring(#muse.playing.notes * muse.playing.interval))
|
||||
else
|
||||
return "Nothing is playing"
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("findtones", {
|
||||
description = "Find tone blocks in the vicinity.",
|
||||
func = function()
|
||||
toneblocks = {}
|
||||
muse.find_toneblocks()
|
||||
|
||||
local len = 0
|
||||
for k, v in pairs(toneblocks) do
|
||||
len = len + 1
|
||||
end
|
||||
|
||||
minetest.display_chat_message("Found " .. tostring(len) .. " out of 25 tones")
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("play", {
|
||||
description = "Play a musical track",
|
||||
params = "<track>",
|
||||
func = function(params)
|
||||
local track = muse.tracks[params]
|
||||
if track then
|
||||
muse.play_track(track)
|
||||
minetest.display_chat_message("Now playing " .. muse.playing.name)
|
||||
else
|
||||
minetest.display_chat_message("Track not found.")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("playing", {
|
||||
description = "Show currently playing track and its progress",
|
||||
func = function()
|
||||
minetest.display_chat_message(muse.get_playing_string())
|
||||
end
|
||||
})
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,70 @@
|
|||
-- CC0/Unlicense Emilia 2020
|
||||
|
||||
-- Optimizes stuff.
|
||||
|
||||
|
||||
woptimize={}
|
||||
|
||||
function woptimize.countents()
|
||||
local obj = minetest.localplayer.get_nearby_objects(10000)
|
||||
ws.dcm("Entity count: "..#obj)
|
||||
end
|
||||
|
||||
|
||||
-- texture is a prefix
|
||||
local function remove_ents(texture)
|
||||
if not minetest.localplayer then return end
|
||||
local obj = minetest.localplayer.get_nearby_objects(10000)
|
||||
|
||||
for i, v in ipairs(obj) do
|
||||
-- CAOs with water/lava textures are droplets
|
||||
--minetest.log("ERROR",v:get_item_textures())
|
||||
--ws.dcm(v:get_item_textures())
|
||||
local txt=v:get_item_textures()
|
||||
if type(txt) == "string" and txt:find(texture) then
|
||||
v:set_visible(false)
|
||||
v:remove(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function remove_hud(name)
|
||||
local player = minetest.localplayer
|
||||
local def
|
||||
local i = -1
|
||||
if not player then return end
|
||||
repeat
|
||||
i = i + 1
|
||||
def = player:hud_get(i)
|
||||
until not def or def.text:find(name)
|
||||
if def then
|
||||
minetest.localplayer:hud_remove(i)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
core.register_on_spawn_particle(function(particle)
|
||||
if minetest.settings:get_bool("noparticles") then return true end
|
||||
end)
|
||||
|
||||
local epoch = os.clock()
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if not minetest.localplayer then return end
|
||||
if os.clock() > epoch + 1 then
|
||||
if minetest.settings:get_bool("optimize_water_drops") then
|
||||
remove_ents("default_water_source")
|
||||
end
|
||||
if minetest.settings:get_bool("optimize_burning") then
|
||||
remove_hud('mcl_burning_hud_flame_animated.png')
|
||||
end
|
||||
epoch = os.clock()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
minetest.register_cheat("NoParticles", "Render", "noparticles")
|
||||
minetest.register_cheat("NoDroplets", "Render", "optimize_water_drops")
|
||||
minetest.register_cheat("NoBurning", "Render", "optimize_burning")
|
|
@ -0,0 +1,3 @@
|
|||
optimize_water_drops (Hide water drops, improves framerates in watery areas) bool false
|
||||
optimize_hearts (Hide damage hearts) bool false
|
||||
noparticles (Do not show particles) bool false
|
|
@ -0,0 +1,160 @@
|
|||
-- CC0/Unlicense system32 2020
|
||||
|
||||
local function parse_coord(c)
|
||||
c = string.split(c, " ")
|
||||
return {x = tonumber(c[1] or 0), y = tonumber(c[2] or 0), z = tonumber(c[3] or 0)}
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("cpeek", {
|
||||
func = function(params)
|
||||
local oldpos = minetest.localplayer:get_pos()
|
||||
|
||||
local c = parse_coord(params)
|
||||
local dist = vector.distance(c, oldpos)
|
||||
local d = tostring(c.x) .. "," .. tostring(c.y) .. "," .. tostring(c.z)
|
||||
local f = "size[10,10]\nlabel[0,0;Can access: " .. tostring(dist < 6) .. "(" .. tostring(dist) .. ")]\nlist[nodemeta:" .. d .. ";main;0,0.5;9,3;]"
|
||||
|
||||
minetest.localplayer:set_pos(c)
|
||||
minetest.show_formspec("ChestPeek", f)
|
||||
minetest.localplayer:set_pos(oldpos)
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
local formspec_template = "size[9,Y]label[0,0;L]button[8,0;1,1;up;^Up^]"
|
||||
local formspec_base = formspec_template:gsub("Y", "4")
|
||||
local formspec_base_label = formspec_template:gsub("Y", "4.5")
|
||||
|
||||
local formspec_item = "\nitem_image_button[X,Y;1,1;I;N;]"
|
||||
local formspec_item_label = formspec_item .. "\nlabel[X,Z;T]"
|
||||
|
||||
local function map(f, t)
|
||||
local out = {}
|
||||
for i, v in ipairs(t) do
|
||||
out[i] = f(v)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
local inventories = {}
|
||||
|
||||
-- include_label because i implemented the label then realized item buttons did it themselves
|
||||
local function make_formspec(name, items, include_label)
|
||||
if items == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
local form = formspec_base
|
||||
if include_label then
|
||||
form = formspec_base_label
|
||||
end
|
||||
|
||||
-- color strip cause yellow is unreadible with default styling
|
||||
form = form:gsub("L", minetest.formspec_escape(minetest.strip_colors(name)))
|
||||
|
||||
for i, v in ipairs(items) do
|
||||
local x = (i - 1) % 9
|
||||
local y = 1 + math.floor((i - 1) / 9) -- +1 for the shulker name
|
||||
|
||||
if include_label then
|
||||
y = y + (y * 0.2) -- shifts each layer down a bit
|
||||
end
|
||||
|
||||
local it = formspec_item
|
||||
if include_label then
|
||||
it = formspec_item_label
|
||||
end
|
||||
|
||||
it = it:gsub("X", x)
|
||||
it = it:gsub("Y", y)
|
||||
if include_label then
|
||||
it = it:gsub("I", v:get_name())
|
||||
it = it:gsub("Z", y + 0.8)
|
||||
it = it:gsub("T", v:get_count())
|
||||
else
|
||||
it = it:gsub("I", v:get_name() .. " " .. tostring(v:get_count()))
|
||||
end
|
||||
|
||||
local item_name = "button" .. tostring(i)
|
||||
it = it:gsub("N", item_name)
|
||||
|
||||
if minetest.get_item_def(v:get_name()).description ~= v:get_description() then
|
||||
it = it .. "tooltip[" .. item_name .. ";" .. v:get_description() .. "]"
|
||||
end
|
||||
|
||||
form = form .. it
|
||||
end
|
||||
|
||||
return form
|
||||
end
|
||||
|
||||
local function get_items(item)
|
||||
local meta = item:get_metadata()
|
||||
local list = minetest.deserialize(meta)
|
||||
|
||||
if list == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local items = map(ItemStack, list)
|
||||
return items
|
||||
end
|
||||
|
||||
local function make_list(name, items, prevent_push)
|
||||
local fs = make_formspec(name, items)
|
||||
|
||||
if not prevent_push then
|
||||
table.insert(inventories, {name = name, items = items})
|
||||
end
|
||||
|
||||
if fs ~= nil then
|
||||
minetest.show_formspec("PeekInventory", fs)
|
||||
end
|
||||
end
|
||||
|
||||
local function show_form(shulker)
|
||||
make_list(shulker:get_description(), get_items(shulker))
|
||||
end
|
||||
|
||||
local function top(list)
|
||||
return list[#list]
|
||||
end
|
||||
|
||||
minetest.register_on_formspec_input(function(formname, fields)
|
||||
if formname == "PeekInventory" then
|
||||
if fields.quit then
|
||||
inventories = {}
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.up and #inventories > 1 then
|
||||
table.remove(inventories)
|
||||
local t = top(inventories)
|
||||
make_list(t.name, t.items, true)
|
||||
return true
|
||||
end
|
||||
|
||||
for k, v in pairs(fields) do
|
||||
if k:find("button") then
|
||||
local idx = tonumber(k:match("([0-9]+)"))
|
||||
local item = top(inventories).items[idx]
|
||||
local iname = item:get_name()
|
||||
if iname:find("mcl_chests:.-_shulker_box") then
|
||||
show_form(top(inventories).items[idx])
|
||||
return true
|
||||
elseif iname:find("mcl_books:.-written_book") then
|
||||
-- to be implemented with bookbot
|
||||
-- bookbot.read(item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("peek", {
|
||||
description = "Peek inside a Mineclone Shulker box.",
|
||||
func = function()
|
||||
show_form(minetest.localplayer:get_wielded_item())
|
||||
end
|
||||
})
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
-- CC0/Unlicense Emilia 2020
|
||||
|
||||
--[[
|
||||
invaction
|
||||
place
|
||||
dig
|
||||
interact
|
||||
--]]
|
||||
|
||||
-- invaction stuff needs to change indices to 1 indexed soon(tm)
|
||||
|
||||
|
||||
-- Queue Interact
|
||||
-- think of it like minetest.after() but with automatic time calculation and a bit more parallel
|
||||
quint = {}
|
||||
|
||||
-- New empty invaction quint
|
||||
function quint.invaction_new()
|
||||
return {start = {}, q = {}, current = {}, last = 0, index = 1}
|
||||
end
|
||||
|
||||
-- Get a global index for an inventory location from part of an invaction
|
||||
local function format_inv(taction)
|
||||
return taction.location .. ";" .. taction.inventory
|
||||
end
|
||||
|
||||
-- Split a global inventory index
|
||||
local function parse_inv(inv)
|
||||
local spl = string.split(inv, ";")
|
||||
return {location = spl[1], inventory = spl[2]}
|
||||
end
|
||||
|
||||
-- Get some useful things from an invaction
|
||||
local function parse_invaction(lists, taction)
|
||||
local idx = format_inv(taction)
|
||||
local slot = taction.slot
|
||||
local itemstack = lists[idx][slot]
|
||||
|
||||
return idx, slot, itemstack
|
||||
end
|
||||
|
||||
-- Simulates an inventory action, performing the collateral operations
|
||||
local function simulate_invaction(lists, invaction)
|
||||
local fidx, fslot, fis = parse_invaction(lists, invaction:to_table().from)
|
||||
local tidx, tslot, tis = parse_invaction(lists, invaction:to_table().to)
|
||||
|
||||
local tcount = invaction:to_table().count
|
||||
if tcount == 0 then
|
||||
tcount = fis:get_count()
|
||||
end
|
||||
|
||||
-- can't do anything
|
||||
if fis:is_empty() then
|
||||
return
|
||||
end
|
||||
|
||||
-- dump
|
||||
if tis:is_empty() then
|
||||
lists[tidx][tslot] = fis
|
||||
lists[fidx][fslot] = ItemStack()
|
||||
return
|
||||
end
|
||||
|
||||
-- swap
|
||||
if ((fis:get_name() ~= tis:get_name())
|
||||
or (fis:get_name() == tis:get_name()
|
||||
and tcount > tis:get_free_space())
|
||||
or (tcount > tis:get_free_space())) then
|
||||
local t = fis
|
||||
lists[fidx][fslot] = tis
|
||||
lists[tidx][tslot] = t
|
||||
return
|
||||
end
|
||||
|
||||
-- fill
|
||||
if fis:get_name() == tis:get_name() and tcount <= tis:get_free_space() then
|
||||
local count = math.min(fis:get_count(), tis:get_free_space(), tcount)
|
||||
|
||||
lists[tidx][tslot]:set_count(tis:get_count() + count)
|
||||
|
||||
if fis:get_count() - count == 0 then
|
||||
lists[fidx][fslot] = ItemStack()
|
||||
else
|
||||
lists[fidx][fslot]:set_count(fis:get_count() - count)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Deepcopy an inventory list
|
||||
local function invlist_copy(list)
|
||||
local o = {}
|
||||
|
||||
for i, v in ipairs(list) do
|
||||
o[i] = ItemStack(v:to_string())
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
-- Add an invlist to a invaction quint if not there already
|
||||
local function insert_invlist(q, taction)
|
||||
local idx = format_inv(taction)
|
||||
if q.start[idx] == nil then
|
||||
local mdata = minetest.get_inventory(taction.location)
|
||||
if mdata then
|
||||
q.start[idx] = mdata[taction.inventory]
|
||||
q.current[idx] = invlist_copy(mdata[taction.inventory])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Enqueue and preview an InventoryAction
|
||||
function quint.invaction_enqueue(q, invaction)
|
||||
insert_invlist(q, invaction:to_table().from)
|
||||
insert_invlist(q, invaction:to_table().to)
|
||||
|
||||
table.insert(q.q, invaction)
|
||||
|
||||
simulate_invaction(q.current, invaction)
|
||||
end
|
||||
|
||||
-- Dump a slot into destination, perform another dump if there is extra
|
||||
local function invaction_dump_slot(q, src, dst, srci, dstbounds)
|
||||
local empty
|
||||
local matching
|
||||
|
||||
local sinv = q.current[format_inv(src)]
|
||||
local dinv = q.current[format_inv(dst)]
|
||||
|
||||
if sinv[srci]:is_empty() then
|
||||
return true
|
||||
end
|
||||
|
||||
for i = dstbounds.min, dstbounds.max do
|
||||
if not empty and dinv[i]:is_empty() then
|
||||
empty = i
|
||||
end
|
||||
|
||||
if not matching and dinv[i]:get_name() == sinv[srci]:get_name() then
|
||||
if dinv[i]:get_free_space() ~= 0 then
|
||||
matching = i
|
||||
end
|
||||
end
|
||||
|
||||
if matching and empty then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if matching then
|
||||
local free = dinv[matching]:get_free_space()
|
||||
local scount = sinv[srci]:get_count()
|
||||
local count = math.min(free, scount)
|
||||
|
||||
local act = InventoryAction("move")
|
||||
act:from(src.location, src.inventory, srci)
|
||||
act:to(dst.location, dst.inventory, matching)
|
||||
act:set_count(count)
|
||||
|
||||
quint.invaction_enqueue(q, act)
|
||||
|
||||
if scount > free then
|
||||
return invaction_dump_slot(q, src, dst, srci, dstbounds)
|
||||
end
|
||||
|
||||
return true
|
||||
elseif empty then
|
||||
local act = InventoryAction("move")
|
||||
act:from(src.location, src.inventory, srci)
|
||||
act:to(dst.location, dst.inventory, empty)
|
||||
quint.invaction_enqueue(q, act)
|
||||
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function rebind(lists, inv, bounds)
|
||||
local invlist = lists[format_inv(inv)]
|
||||
|
||||
if not bounds then
|
||||
bounds = {min = 0, max = 0}
|
||||
end
|
||||
|
||||
if bounds.max == 0 then
|
||||
bounds.max = #invlist
|
||||
end
|
||||
|
||||
bounds.min = math.max(bounds.min, 1)
|
||||
bounds.max = math.min(bounds.max, #invlist)
|
||||
|
||||
return bounds
|
||||
end
|
||||
|
||||
-- Dump from src to dst
|
||||
-- src and dest are in the format of {location = "", inventory = ""}
|
||||
-- like {location = "current_player", inventory = "main"}
|
||||
-- srcbounds and dstbounds are inclusive beginning and ends to the selectible invslots
|
||||
-- in the form {min = n, max = n}, if max is 0 it is changed to the maximum index
|
||||
function quint.invaction_dump(q, src, dst, srcbounds, dstbounds)
|
||||
if src.location .. src.inventory == dst.location .. dst.inventory then
|
||||
return
|
||||
end
|
||||
|
||||
insert_invlist(q, src)
|
||||
insert_invlist(q, dst)
|
||||
|
||||
srcbounds = rebind(q.current, src, srcbounds)
|
||||
dstbounds = rebind(q.current, dst, dstbounds)
|
||||
|
||||
for i = srcbounds.min, srcbounds.max do
|
||||
if not invaction_dump_slot(q, src, dst, i, dstbounds) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- Remake a invaction quint up to index, refreshing the starts
|
||||
function quint.invaction_remake(q, index)
|
||||
local t = quint.invaction_new()
|
||||
|
||||
for i = 1, index do
|
||||
invaction_enqueue(t, q.q[i])
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
-- Preview an invaction quint after the first n (index) actions
|
||||
function quint.invaction_view_state_at(q, index)
|
||||
local t = quint.invaction_remake(q, index)
|
||||
|
||||
return t.current
|
||||
end
|
||||
|
||||
-- Refresh starts and get new currents
|
||||
function quint.invaction_refresh(q)
|
||||
local t = quint.invaction_remake(q, #q.q)
|
||||
q.start = t.start
|
||||
q.current = t.current
|
||||
end
|
||||
|
||||
quint.invaction_gsteps = {}
|
||||
|
||||
-- Apply an invaction quint, with optional delay
|
||||
function quint.invaction_apply(q, delay)
|
||||
q.delay = delay
|
||||
|
||||
if not delay or delay == 0 then
|
||||
for i, v in ipairs(q.q) do
|
||||
v:apply()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
table.insert(quint.invaction_gsteps, q)
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
local dead = {}
|
||||
|
||||
local ctime = os.clock()
|
||||
|
||||
for i, v in ipairs(quint.invaction_gsteps) do
|
||||
if not v.delay or ctime >= v.last + v.delay then
|
||||
if v.delay then
|
||||
v.last = v.last + v.delay
|
||||
end
|
||||
|
||||
if v.q[v.index] then
|
||||
v.q[v.index]:apply()
|
||||
v.index = v.index + 1
|
||||
else
|
||||
table.insert(dead, 1, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i, v in ipairs(dead) do
|
||||
table.remove(quint.invaction_gsteps, v)
|
||||
end
|
||||
end)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue