Compare commits
7 Commits
master
...
bzoss_play
Author | SHA1 | Date |
---|---|---|
Brandon | 55551069b0 | |
Brandon | 3bbe7a6826 | |
Brandon | 796c45d4b3 | |
Brandon | 0e797e2c3f | |
Brandon | 53d52b3cac | |
Brandon | 0637adf7ef | |
Brandon | 266fd6fc71 |
|
@ -5,47 +5,47 @@ Wow, thank you! :-)
|
|||
But first, some things to note:
|
||||
|
||||
MineClone 2's development target is to make a free software clone of Minecraft,
|
||||
***version 1.12***, ***PC edition***, *** + Optifine features supported by the Minetest Engine ***.
|
||||
***version 1.11***, ***PC edition***.
|
||||
|
||||
MineClone 2 is maintained by two persons. Namely, kay27 and EliasFleckenstein. You can find us
|
||||
in the Minetest forums (forums.minetest.net), in IRC in the #minetest
|
||||
MineClone 2 is maintained by one person. Namely, Wuzzy. You can find me,
|
||||
Wuzzy, in the Minetest forums (forums.minetest.net), in IRC in the #minetest
|
||||
channel on irc.freenode.net. And finally, you can send e-mails to
|
||||
<eliasfleckenstein@web.de> or <kay27@bk.ru>.
|
||||
<Wuzzy2@mail.ru>.
|
||||
|
||||
There is **no** guarantee we will accept anything from anybody.
|
||||
There is **no** guarantee I will accept anything from anybody.
|
||||
|
||||
By sending us patches or asking us to include your changes in this game,
|
||||
By sending me patches or asking me to include your changes in this game,
|
||||
you agree that they fall under the terms of the LGPLv2.1, which basically
|
||||
means they will become part of a free software.
|
||||
|
||||
## The suggested workflow
|
||||
We don't **dictate** your workflow, but in order to work with us in an efficient
|
||||
way, you can follow these suggestions:
|
||||
I don't **dictate** your workflow, but in order to work with me in an efficient
|
||||
way, you can follow my suggestions.
|
||||
|
||||
For small and medium changes:
|
||||
|
||||
* Fork the repository
|
||||
* Do your change in a new branch
|
||||
* Upload the repository somewhere where it can be accessed from the Internet and
|
||||
notify us
|
||||
notify me
|
||||
|
||||
For small changes, sending us a patch is also good.
|
||||
For small changes, sending me a patch is also good.
|
||||
|
||||
For big changes: Same as above, but consider notifying us first to avoid
|
||||
For big changes: Same as above, but consider notifying me first to avoid
|
||||
duplicate work and possible tears of rejection. ;-)
|
||||
|
||||
For trusted people, we might give them direct commit access to this
|
||||
For people that I trust, I might give them direct commit access to this
|
||||
repository. In this case, you obviously don't need to fork, but you still
|
||||
need to show your contributions align with the project goals. We still
|
||||
reserve the right to revert everything that we don't like.
|
||||
For bigger changes, we strongly recommend to use feature branches and
|
||||
need to show your contributions align with the project goals. I still
|
||||
reserve the right to revert everything that I don't like.
|
||||
For bigger changes, I strongly recommend to use feature branches and
|
||||
discuss with me first.
|
||||
|
||||
Contributors will be credited in `README.md`.
|
||||
|
||||
## Quality remarks
|
||||
Again: There is ***no*** guarantee we will accept anything from anybody.
|
||||
But we will gladly take in code from others when we feel it saves us work
|
||||
Again: There is ***no*** guarantee I will accept anything from anybody.
|
||||
But I will gladly take in code from others when I feel it saves me work
|
||||
in the long run.
|
||||
|
||||
### Inclusion criteria
|
||||
|
@ -79,18 +79,4 @@ Depending on what you add, the chances for inclusion vary:
|
|||
## Reporting bugs
|
||||
Report all bugs and missing Minecraft features here:
|
||||
|
||||
<https://git.minetest.land/MineClone2/MineClone2/issues>
|
||||
|
||||
## Direct discussion
|
||||
We have an IRC channel! Join us on #mineclone2 in freenode.net.
|
||||
|
||||
<ircs://irc.freenode.net:6697/#mineclone2>
|
||||
|
||||
## Creating releases
|
||||
* Launch MineClone2 to make sure it still runs
|
||||
* Update the version number in README.md
|
||||
* Use `git tag <version number>` to tag the latest commit with the version number
|
||||
* Push to repo (don't forget `--tags`!)
|
||||
* Update ContentDB (https://content.minetest.net/packages/Wuzzy/mineclone2/)
|
||||
* Update first post in forum thread (https://forum.minetest.net/viewtopic.php?f=50&t=16407)
|
||||
* Post release announcement and changelog in forums
|
||||
<https://git.minetest.land/Wuzzy/MineClone2/issues>
|
||||
|
|
|
@ -70,7 +70,6 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
|||
* `coral_fan=X`: Coral fan (1 = alive, 2 = dead)
|
||||
* `coral_block=X`: Coral block (1 = alive, 2 = dead)
|
||||
* `coral_species=X`: Specifies the species of a coral; equal X means equal species
|
||||
* `set_on_fire=X`: Sets any (not fire-resistant) mob or player on fire for X seconds when touching
|
||||
|
||||
#### Footnotes
|
||||
|
||||
|
@ -97,8 +96,6 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
|||
* `carpet=1:` (Wool) carpet
|
||||
* `stick=1`: Stick
|
||||
* `water_bucket=1`: Bucket containing a liquid of group “water”
|
||||
* `enchantability=X`: How good the enchantments are the item gets (1 equals book)
|
||||
* `enchanted=1`: The item is already enchanted, meaning that it can't be enchanted using an enchanting table
|
||||
|
||||
### Material groups
|
||||
|
||||
|
@ -200,7 +197,6 @@ These groups are used mostly for informational purposes
|
|||
* `building_block=1`: Block is a building block
|
||||
* `deco_block=1`: Block is a decorational block
|
||||
|
||||
|
||||
## Fake item groups
|
||||
These groups put similar items together which should all be treated by the gameplay or the GUI as a single item.
|
||||
You should not add custom items to these groups for no good reason, this is likely to cause a ton of conflicts.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Missing features in Minetest to recreate Minecraft features
|
||||
|
||||
A side goal of the MineClone 2 project is to find any shortcomings of Minetest which make it impossible to recreate a Minecraft feature exactly.
|
||||
This file lists some of the missing features in Minetest which MineClone 2 would require.
|
||||
This file lists some of the missing features in Minetest which MineClone 2 would require.MineClone 2 would require.MineClone 2 would require.MineClone 2 would require.
|
||||
|
||||
## No workaround possible
|
||||
For these features, no easy Lua workaround could be found.
|
||||
|
@ -20,6 +20,7 @@ For these features, no easy Lua workaround could be found.
|
|||
## Interface
|
||||
- Inventory: Hold down right mouse button while holding an item stack to drop items into the slots as you move the mouse. Makes crafting MUCH faster
|
||||
- Sneak+Leftclick on crafting output crafts as many items as possible and immediately puts it into the player inventory ([issue 5211](https://github.com/minetest/minetest/issues/5211))
|
||||
- Sneak+click on inventory slot should be able to put items into additional “fallback inventories” if the first inventory is full. Required for large chests
|
||||
- Sneak+click puts items in different inventories depending on the item type (maybe group-based)? Required for sneak-clicking to armor slots
|
||||
|
||||
## Workaround theoretically possible
|
||||
|
@ -34,7 +35,6 @@ For these features, a workaround (or hack ;-)) by using Lua is theoretically pos
|
|||
- Set frequency in which players lose breath. 2 seconds are hardcoded in Minetest, in Minecraft it's 1 second
|
||||
- Set damage frequency of `damage_per_second`. In Minecraft many things damage players every half-second rather than every second
|
||||
- Possible to damage players directly when they are with the head inside. This allows to add Minecraft-like suffocation
|
||||
- Sneak+click on inventory slot should be able to put items into additional “fallback inventories” if the first inventory is full. Useful for large chests
|
||||
|
||||
#### Nice-to-haye
|
||||
- Utility function to rotate pillar-like nodes, requiring only 3 possible orientations (X, Y, Z). Basically this is `minetest.rotate_node` but with less orientations; the purpur pillar would mess up if a mirrored rotation would be possible. This is already implemented in MCL2, See `mcl_util` for more infos
|
||||
|
|
32
README.md
|
@ -1,8 +1,8 @@
|
|||
# MineClone 2
|
||||
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
||||
Developed by many people. Not developed or endorsed by Mojang AB.
|
||||
Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB.
|
||||
|
||||
Version: 0.70.0
|
||||
Version: 0.66.2
|
||||
|
||||
### Gameplay
|
||||
You start in a randomly-generated world made entirely of cubes. You can explore
|
||||
|
@ -14,10 +14,9 @@ Or you can play in “creative mode” in which you can build almost anything in
|
|||
|
||||
#### Gameplay summary
|
||||
|
||||
* Sandbox-style gameplay, no goals
|
||||
* Sandbox-style gameplay, no goals (for now)
|
||||
* Survive: Fight against hostile monsters and hunger
|
||||
* Mine for ores and other treasures
|
||||
* Magic: Gain experience and enchant your tools
|
||||
* Use the collected blocks to create great buildings, your imagination is the limit
|
||||
* Collect flowers (and other dye sources) and colorize your world
|
||||
* Find some seeds and start farming
|
||||
|
@ -86,8 +85,7 @@ Minetest to learn more.
|
|||
## Project description
|
||||
The main goal of **MineClone 2** is to be a clone of Minecraft and to be released as free software.
|
||||
|
||||
* **Target of development: Minecraft, PC Edition, version 1.12** (later known as “Java Edition”)
|
||||
* MineClone2 also includes Optifine features supported by the Minetest
|
||||
* **Target of development: Minecraft, PC Edition, version 1.11** (later known as “Java Edition”)
|
||||
* Features of later Minecraft versions might sneak in, but they have a low priority
|
||||
* In general, Minecraft is aimed to be cloned as good as Minetest currently permits (no hacks)
|
||||
* Cloning the gameplay has highest priority
|
||||
|
@ -104,7 +102,7 @@ big bugs (such as “missing node” errors or even crashes).
|
|||
The following main features are available:
|
||||
|
||||
* Tools, weapons
|
||||
* Armor
|
||||
* Armor (unbalanced)
|
||||
* Crafting system: 2×2 grid, crafting table (3×3 grid), furnace, including a crafting guide
|
||||
* Chests, large chests, ender chests, shulker boxes
|
||||
* Furnaces, hoppers
|
||||
|
@ -118,10 +116,6 @@ The following main features are available:
|
|||
* The Nether, a fiery underworld in another dimension
|
||||
* Redstone circuits (partially)
|
||||
* Minecarts (partial)
|
||||
* Status effects (partial)
|
||||
* Experience
|
||||
* Enchanting
|
||||
* Brewing, potions, tipped arrow (partial)
|
||||
* Boats
|
||||
* Fire
|
||||
* Buidling blocks: Stairs, slabs, doors, trapdoors, fences, fence gates, walls
|
||||
|
@ -146,9 +140,14 @@ The following main features are available:
|
|||
The following features are incomplete:
|
||||
|
||||
* Generated structures (especially villages)
|
||||
* NPCs
|
||||
* Some monsters and animals
|
||||
* Redstone-related things
|
||||
* The End
|
||||
* Enchanting
|
||||
* Experience
|
||||
* Status effects
|
||||
* Brewing, potions, tipped arrows
|
||||
* Special minecarts
|
||||
* A couple of non-trivial blocks and items
|
||||
|
||||
|
@ -183,7 +182,7 @@ Technical differences from Minecraft:
|
|||
## Reporting bugs
|
||||
Please report all bugs and missing Minecraft features here:
|
||||
|
||||
<https://git.minetest.land/MineClone2/MineClone2/issues>
|
||||
<https://git.minetest.land/Wuzzy/MineClone2/issues>
|
||||
|
||||
## Other readme files
|
||||
|
||||
|
@ -196,7 +195,7 @@ Please report all bugs and missing Minecraft features here:
|
|||
There are so many people to list (sorry). Check out the respective mod directories for details. This section is only a rough overview of the core authors of this game.
|
||||
|
||||
### Coding
|
||||
* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082): Main programmer of most mods (retired)
|
||||
* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082): Main programmer of most mods
|
||||
* davedevils: Creator of MineClone on which MineClone 2 is based on
|
||||
* [ex-bart](https://github.com/ex-bart): Redstone comparators
|
||||
* [Rootyjr](https://github.com/Rootyjr): Fishing rod and bugfixes
|
||||
|
@ -204,9 +203,6 @@ There are so many people to list (sorry). Check out the respective mod directori
|
|||
* [ryvnf](https://github.com/ryvnf): Explosion mechanics
|
||||
* MysticTempest: Bugfixes
|
||||
* [bzoss](https://github.com/bzoss): Status effects, potions, brewing stand
|
||||
* kay27 <kay27@bk.ru>: Experience system, bugfixes, optimizations (Current maintainer)
|
||||
* [EliasFleckenstein03](https://github.com/EliasFleckenstein03): End crystals, enchanting, burning mobs / players, animated chests, bugfixes (Current maintainer)
|
||||
* 2mac: Fix bug with powered rail
|
||||
* Lots of other people: TO BE WRITTEN (see mod directories for details)
|
||||
|
||||
#### Mod credits (summary)
|
||||
|
@ -252,7 +248,6 @@ Various sources. See the respective mod directories for details.
|
|||
### Special thanks
|
||||
|
||||
* davedevils for starting MineClone, the original version of this game
|
||||
* Wuzzy for starting and maintaining MineClone2 for several years
|
||||
* celeron55 for creating Minetest
|
||||
* Minetest's modding community for providing a huge selection of mods, some of which ended up in MineClone 2
|
||||
* Jordach for the jukebox music compilation from Big Freaking Dig
|
||||
|
@ -264,6 +259,7 @@ Various sources. See the respective mod directories for details.
|
|||
|
||||
## Info for programmers
|
||||
You find interesting and useful infos in `API.md`.
|
||||
This project is currently mostly a one-person project.
|
||||
|
||||
## Legal information
|
||||
This is a fan game, not developed or endorsed by Mojang AB.
|
||||
|
@ -272,7 +268,7 @@ Copying is an act of love. Please copy and share! <3
|
|||
Here's the detailed legalese for those who need it:
|
||||
|
||||
### License of source code
|
||||
MineClone 2 (by kay27, EliasFleckenstein, Wuzzy, davedevils and countless others)
|
||||
MineClone 2 (by Wuzzy, davedevils and countless others)
|
||||
is an imitation of Minecraft.
|
||||
|
||||
MineClone 2 is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -31,5 +31,3 @@ mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_de
|
|||
|
||||
# MCL2-specific stuff
|
||||
keepInventory = false
|
||||
|
||||
dedicated_server_step = 0.001
|
||||
|
|
|
@ -18,7 +18,7 @@ digging times in seconds. These digging times can be then added verbatim into th
|
|||
Example:
|
||||
mcl_autogroup.digtimes.pickaxey_dig_diamond[1] = 0.2
|
||||
|
||||
→ This means that when a node has been assigned the group “pickaxey_dig_diamond=1”, it can be dug by the
|
||||
→ This menas that when a node has been assigned the group “pickaxey_dig_diamond=1”, it can be dug by the
|
||||
diamond pickaxe in 0.2 seconds.
|
||||
|
||||
|
||||
|
@ -44,7 +44,6 @@ local divisors = {
|
|||
["shearsy_wool"] = 5,
|
||||
["swordy_cobweb"] = 15,
|
||||
}
|
||||
local max_efficiency_level = 5
|
||||
|
||||
mcl_autogroup = {}
|
||||
mcl_autogroup.digtimes = {}
|
||||
|
@ -54,18 +53,11 @@ for m=1, #materials do
|
|||
for g=1, #basegroups do
|
||||
mcl_autogroup.digtimes[basegroups[g].."_dig_"..materials[m]] = {}
|
||||
mcl_autogroup.creativetimes[basegroups[g].."_dig_"..materials[m]] = {}
|
||||
for e=1, max_efficiency_level do
|
||||
mcl_autogroup.digtimes[basegroups[g].."_dig_"..materials[m].."_efficiency_"..e] = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
for g=1, #minigroups do
|
||||
mcl_autogroup.digtimes[minigroups[g].."_dig"] = {}
|
||||
mcl_autogroup.creativetimes[minigroups[g].."_dig"] = {}
|
||||
for e=1, max_efficiency_level do
|
||||
mcl_autogroup.digtimes[minigroups[g].."_dig_efficiency_"..e] = {}
|
||||
mcl_autogroup.creativetimes[minigroups[g].."_dig_efficiency_"..e] = {}
|
||||
end
|
||||
end
|
||||
|
||||
local overwrite = function()
|
||||
|
@ -88,7 +80,7 @@ local overwrite = function()
|
|||
groups_changed = true
|
||||
end
|
||||
|
||||
local function calculate_group(hardness, material, diggroup, newgroups, actual_rating, expected_rating, efficiency)
|
||||
local function calculate_group(hardness, material, diggroup, newgroups, actual_rating, expected_rating)
|
||||
local time, validity_factor
|
||||
if actual_rating >= expected_rating then
|
||||
-- Valid tool
|
||||
|
@ -97,20 +89,14 @@ local overwrite = function()
|
|||
-- Wrong tool (higher digging time)
|
||||
validity_factor = 5
|
||||
end
|
||||
local speed_multiplier = divisors[material]
|
||||
if efficiency then
|
||||
speed_multiplier = speed_multiplier + efficiency * efficiency + 1
|
||||
end
|
||||
time = (hardness * validity_factor) / speed_multiplier
|
||||
time = (hardness * validity_factor) / divisors[material]
|
||||
if time <= 0.05 then
|
||||
time = 0
|
||||
else
|
||||
time = math.ceil(time * 20) / 20
|
||||
end
|
||||
table.insert(mcl_autogroup.digtimes[diggroup], time)
|
||||
if not efficiency then
|
||||
table.insert(mcl_autogroup.creativetimes[diggroup], 0)
|
||||
end
|
||||
table.insert(mcl_autogroup.creativetimes[diggroup], 0)
|
||||
newgroups[diggroup] = #mcl_autogroup.digtimes[diggroup]
|
||||
return newgroups
|
||||
end
|
||||
|
@ -127,9 +113,6 @@ local overwrite = function()
|
|||
for g=1,#materials do
|
||||
local diggroup = basegroup.."_dig_"..materials[g]
|
||||
newgroups = calculate_group(hardness, materials[g], diggroup, newgroups, g, ndef.groups[basegroup])
|
||||
for e=1,max_efficiency_level do
|
||||
newgroups = calculate_group(hardness, materials[g], diggroup .. "_efficiency_" .. e, newgroups, g, ndef.groups[basegroup], e)
|
||||
end
|
||||
groups_changed = true
|
||||
end
|
||||
end
|
||||
|
@ -151,9 +134,6 @@ local overwrite = function()
|
|||
or
|
||||
(ndef.groups[minigroup] and minigroup ~= "swordy_cobweb" and minigroup ~= "shearsy_wool") then
|
||||
newgroups = calculate_group(hardness, minigroup, diggroup, newgroups, ar, 1)
|
||||
for e=1,max_efficiency_level do
|
||||
newgroups = calculate_group(hardness, minigroup, diggroup .. "_efficiency_" .. e, newgroups, ar, 1, e)
|
||||
end
|
||||
groups_changed = true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,10 +32,6 @@ local STEP_LENGTH = 0.3
|
|||
-- How many rays to compute entity exposure to explosion
|
||||
local N_EXPOSURE_RAYS = 16
|
||||
|
||||
-- Nodes having a blast resistance of this value or higher are treated as
|
||||
-- indestructible
|
||||
local INDESTRUCT_BLASTRES = 1000000
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
-- Store blast resistance values by content ids to improve performance.
|
||||
for name, def in pairs(minetest.registered_nodes) do
|
||||
|
@ -128,7 +124,7 @@ local function add_particles(pos, radius)
|
|||
maxexptime = 1.0,
|
||||
minsize = radius * 0.5,
|
||||
maxsize = radius * 1.0,
|
||||
texture = "mcl_particles_smoke.png",
|
||||
texture = "tnt_smoke.png",
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -139,21 +135,14 @@ end
|
|||
-- strength - The strength of each ray
|
||||
-- raydirs - The directions for each ray
|
||||
-- radius - The maximum distance each ray will go
|
||||
-- info - Table containing information about explosion
|
||||
-- puncher - object that punches other objects (optional)
|
||||
--
|
||||
-- Values in info:
|
||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
||||
-- fire - If true, 1/3 nodes become fire
|
||||
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||
-- max_blast_resistance - The explosion will treat all non-indestructible nodes
|
||||
-- as having a blast resistance of no more than this
|
||||
-- value
|
||||
-- fire - If true, 1/3 of destroyed nodes become fire
|
||||
-- puncher - object that punches other objects (optional)
|
||||
--
|
||||
-- Note that this function has been optimized, it contains code which has been
|
||||
-- inlined to avoid function calls and unnecessary table creation. This was
|
||||
-- measured to give a significant performance increase.
|
||||
local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||
local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire, puncher, creative_enabled)
|
||||
local vm = minetest.get_voxel_manip()
|
||||
|
||||
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
||||
|
@ -175,49 +164,39 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
|||
local data = vm:get_data()
|
||||
local destroy = {}
|
||||
|
||||
local drop_chance = info.drop_chance
|
||||
local fire = info.fire
|
||||
local max_blast_resistance = info.max_blast_resistance
|
||||
|
||||
-- Trace rays for environment destruction
|
||||
if info.griefing then
|
||||
for i = 1, #raydirs do
|
||||
local rpos_x = pos.x
|
||||
local rpos_y = pos.y
|
||||
local rpos_z = pos.z
|
||||
local rdir_x = raydirs[i].x
|
||||
local rdir_y = raydirs[i].y
|
||||
local rdir_z = raydirs[i].z
|
||||
local rstr = (0.7 + math.random() * 0.6) * strength
|
||||
for i = 1, #raydirs do
|
||||
local rpos_x = pos.x
|
||||
local rpos_y = pos.y
|
||||
local rpos_z = pos.z
|
||||
local rdir_x = raydirs[i].x
|
||||
local rdir_y = raydirs[i].y
|
||||
local rdir_z = raydirs[i].z
|
||||
local rstr = (0.7 + math.random() * 0.6) * strength
|
||||
|
||||
for r = 0, math.ceil(radius * (1.0 / STEP_LENGTH)) do
|
||||
local npos_x = math.floor(rpos_x + 0.5)
|
||||
local npos_y = math.floor(rpos_y + 0.5)
|
||||
local npos_z = math.floor(rpos_z + 0.5)
|
||||
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
||||
npos_x - emin_x + 1
|
||||
for r = 0, math.ceil(radius * (1.0 / STEP_LENGTH)) do
|
||||
local npos_x = math.floor(rpos_x + 0.5)
|
||||
local npos_y = math.floor(rpos_y + 0.5)
|
||||
local npos_z = math.floor(rpos_z + 0.5)
|
||||
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
||||
npos_x - emin_x + 1
|
||||
|
||||
local cid = data[idx]
|
||||
local br = node_blastres[cid]
|
||||
if br < INDESTRUCT_BLASTRES and br > max_blast_resistance then
|
||||
br = max_blast_resistance
|
||||
end
|
||||
local cid = data[idx]
|
||||
local br = node_blastres[cid]
|
||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
||||
|
||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
||||
rpos_z = rpos_z + STEP_LENGTH * rdir_z
|
||||
|
||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
||||
rpos_z = rpos_z + STEP_LENGTH * rdir_z
|
||||
rstr = rstr - 0.75 * STEP_LENGTH - (br + 0.3) * STEP_LENGTH
|
||||
|
||||
rstr = rstr - 0.75 * STEP_LENGTH - (br + 0.3) * STEP_LENGTH
|
||||
if rstr <= 0 then
|
||||
break
|
||||
end
|
||||
|
||||
if rstr <= 0 then
|
||||
break
|
||||
end
|
||||
|
||||
if cid ~= minetest.CONTENT_AIR and not minetest.is_protected({x = npos_x, y = npos_y, z = npos_z}, "") then
|
||||
destroy[hash] = idx
|
||||
end
|
||||
if cid ~= minetest.CONTENT_AIR then
|
||||
destroy[hash] = idx
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -255,9 +234,9 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
|||
local z_len = math.abs(z2 - z1)
|
||||
|
||||
-- Move object position to the center of its bounding box
|
||||
opos.x = opos.x + 0.5 * (x1 + x2)
|
||||
opos.y = opos.y + 0.5 * (y1 + y2)
|
||||
opos.z = opos.z + 0.5 * (z1 + z2)
|
||||
opos.x = opos.x + x1 + x2
|
||||
opos.y = opos.y + y1 + y2
|
||||
opos.z = opos.z + z1 + z2
|
||||
|
||||
-- Count number of rays from collision box which are unobstructed
|
||||
local count = N_EXPOSURE_RAYS
|
||||
|
@ -305,40 +284,20 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
|||
impact = 0
|
||||
end
|
||||
local damage = math.floor((impact * impact + impact) * 7 * strength + 1)
|
||||
local source = puncher or obj
|
||||
|
||||
local sleep_formspec_doesnt_close_mt53 = false
|
||||
if obj:is_player() then
|
||||
local name = obj:get_player_name()
|
||||
if mcl_beds then
|
||||
local meta = obj:get_meta()
|
||||
if meta:get_string("mcl_beds:sleeping") == "true" then
|
||||
minetest.close_formspec(name, "") -- ABSOLUTELY NECESSARY FOR MT5.3 -- TODO: REMOVE THIS IN THE FUTURE
|
||||
sleep_formspec_doesnt_close_mt53 = true
|
||||
end
|
||||
end
|
||||
if mod_death_messages then
|
||||
mcl_death_messages.player_damage(obj, S("@1 was caught in an explosion.", name))
|
||||
end
|
||||
if rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[name] = "explosion"
|
||||
end
|
||||
if mod_death_messages and obj:is_player() then
|
||||
mcl_death_messages.player_damage(obj, S("@1 was caught in an explosion.", obj:get_player_name()))
|
||||
end
|
||||
local source = puncher
|
||||
if not source then
|
||||
source = obj
|
||||
end
|
||||
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1,
|
||||
fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
||||
|
||||
if sleep_formspec_doesnt_close_mt53 then
|
||||
minetest.after(0.3, function(obj, damage, impact, punch_dir) -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
|
||||
if not obj then return end
|
||||
obj:punch(obj, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
||||
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
end, obj, damage, impact, vector.new(punch_dir))
|
||||
else
|
||||
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
||||
|
||||
if obj:is_player() then
|
||||
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
elseif ent.tnt_knockback then
|
||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
end
|
||||
if obj:is_player() then
|
||||
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
elseif ent.tnt_knockback then
|
||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -348,14 +307,14 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
|||
|
||||
-- Remove destroyed blocks and drop items
|
||||
for hash, idx in pairs(destroy) do
|
||||
local do_drop = math.random() <= drop_chance
|
||||
local do_drop = not creative_enabled and math.random() <= drop_chance
|
||||
local on_blast = node_on_blast[data[idx]]
|
||||
local remove = true
|
||||
|
||||
if do_drop or on_blast ~= nil then
|
||||
local npos = minetest.get_position_from_hash(hash)
|
||||
if on_blast ~= nil then
|
||||
on_blast(npos, 1.0, do_drop)
|
||||
on_blast(npos, 1.0)
|
||||
remove = false
|
||||
else
|
||||
local name = minetest.get_name_from_content_id(data[idx])
|
||||
|
@ -398,6 +357,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
|||
-- Log explosion
|
||||
minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
|
||||
' with strength ' .. strength .. ' and radius ' .. radius)
|
||||
|
||||
end
|
||||
|
||||
-- Create an explosion with strength at pos.
|
||||
|
@ -405,24 +365,16 @@ end
|
|||
-- Parameters:
|
||||
-- pos - The position where the explosion originates from
|
||||
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
||||
-- info - Table containing information about explosion
|
||||
-- info - Table containing information about explosion.
|
||||
-- puncher - object that is reported as source of punches/damage (optional)
|
||||
--
|
||||
-- Values in info:
|
||||
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
||||
-- explosion (default: 1.0 / strength)
|
||||
-- max_blast_resistance - If specified the explosion will treat all
|
||||
-- non-indestructible nodes as having a blast resistance
|
||||
-- of no more than this value
|
||||
-- sound - If true, the explosion will play a sound (default: true)
|
||||
-- particles - If true, the explosion will create particles (default: true)
|
||||
-- explosion (defaults to 1.0 / strength)
|
||||
-- no_sound - If true then the explosion will not play a sound
|
||||
-- no_particle - If true then the explosion will not create particles
|
||||
-- fire - If true, 1/3 nodes become fire (default: false)
|
||||
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||
function mcl_explosions.explode(pos, strength, info, puncher)
|
||||
if info == nil then
|
||||
info = {}
|
||||
end
|
||||
|
||||
-- The maximum blast radius (in the air)
|
||||
local radius = math.ceil(1.3 * strength / (0.3 * 0.75) * 0.3)
|
||||
|
||||
|
@ -431,27 +383,13 @@ function mcl_explosions.explode(pos, strength, info, puncher)
|
|||
end
|
||||
local shape = sphere_shapes[radius]
|
||||
|
||||
-- Default values
|
||||
if info.drop_chance == nil then info.drop_chance = 1 / strength end
|
||||
if info.particles == nil then info.particles = true end
|
||||
if info.sound == nil then info.sound = true end
|
||||
if info.fire == nil then info.fire = false end
|
||||
if info.griefing == nil then info.griefing = true end
|
||||
if info.max_blast_resistance == nil then
|
||||
info.max_blast_resistance = INDESTRUCT_BLASTRES
|
||||
end
|
||||
local creative_enabled = minetest.is_creative_enabled("")
|
||||
trace_explode(pos, strength, shape, radius, (info and info.drop_chance) or 1 / strength, info.fire == true, puncher, creative_enabled)
|
||||
|
||||
-- Dont do drops in creative mode
|
||||
if minetest.is_creative_enabled("") then
|
||||
info.drop_chance = 0
|
||||
end
|
||||
|
||||
trace_explode(pos, strength, shape, radius, info, puncher)
|
||||
|
||||
if info.particles then
|
||||
if not (info and info.no_sound) then
|
||||
add_particles(pos, radius)
|
||||
end
|
||||
if info.sound then
|
||||
if not (info and info.no_particle) then
|
||||
minetest.sound_play("tnt_explode", {
|
||||
pos = pos, gain = 1.0,
|
||||
max_hear_distance = strength * 16
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
# textdomain:mcl_explosions
|
||||
@1 was caught in an explosion.=@1 a été pris dans une explosion.
|
|
@ -1,2 +0,0 @@
|
|||
# textdomain:mcl_explosions
|
||||
@1 was caught in an explosion.=@1 не удалось пережить взрыва.
|
|
@ -1,4 +1,3 @@
|
|||
name = mcl_explosions
|
||||
description = A common API to create explosions.
|
||||
depends = mcl_particles
|
||||
optional_depends = mcl_fire
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
-- Some global variables (don't overwrite them!)
|
||||
mcl_vars = {}
|
||||
|
||||
mcl_vars.redstone_tick = 0.1
|
||||
|
||||
--- GUI / inventory menu settings
|
||||
mcl_vars.gui_slots = "listcolors[#9990;#FFF7;#FFF0;#000;#FFF]"
|
||||
-- nonbg is added as formspec prepend in mcl_formspec_prepend
|
||||
|
@ -25,64 +23,8 @@ mcl_vars.inventory_header = ""
|
|||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local minecraft_height_limit = 256
|
||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
local singlenode = mg_name == "singlenode"
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_vars.MAP_BLOCKSIZE = math.max(1, core.MAP_BLOCKSIZE or 16)
|
||||
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||
local chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_max_pos = central_chunk_min_pos + chunk_size_in_nodes - 1
|
||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math.floor((coordinate_to_block(x) + central_chunk_offset) / mcl_vars.chunksize)
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_vars.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
if not superflat and not singlenode then
|
||||
if not superflat then
|
||||
-- Normal mode
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
|
@ -103,14 +45,6 @@ if not superflat and not singlenode then
|
|||
mcl_vars.mg_lava = true
|
||||
mcl_vars.mg_bedrock_is_rough = true
|
||||
|
||||
elseif singlenode then
|
||||
mcl_vars.mg_overworld_min = -66
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
else
|
||||
-- Classic superflat
|
||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||
|
@ -127,7 +61,7 @@ else
|
|||
mcl_vars.mg_bedrock_is_rough = false
|
||||
end
|
||||
|
||||
mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max
|
||||
mcl_vars.mg_overworld_max = 31000
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
|
@ -174,3 +108,4 @@ minetest.craftitemdef_default.stack_max = 64
|
|||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||
math.randomseed(os.time())
|
||||
|
||||
|
||||
|
|
|
@ -11,15 +11,12 @@ Parameters:
|
|||
stacks_max = 3, -- Maximum number of item stacks to get. Default: 1
|
||||
items = { -- Table of possible loot items. This function selects between stacks_min and stacks_max of these.
|
||||
{
|
||||
weight = 5, -- Likelihood of this item being selected (see below). Optional (default: 1)
|
||||
|
||||
itemstack = ItemStack("example:item1"), -- Itemstack to select
|
||||
-- OR
|
||||
itemstring = "example:item1", -- Which item to select
|
||||
amount_min = 1, -- Minimum size of itemstack. Must not be larger than 6553. Optional (default: 1)
|
||||
amount_max = 10, -- Maximum size of item stack. Must not be larger than item definition's stack_max or 6553. Optional (default: 1)
|
||||
wear_min = 1, -- Minimum wear value. Must be at least 1. Optional (default: no wear)
|
||||
wear_max = 1, -- Maxiumum wear value. Must be at least 1. Optional (default: no wear)
|
||||
weight = 5, -- Likelihood of this item being selected (see below). Optional (default: 1)
|
||||
},
|
||||
{ -- more tables like above, one table per item stack }
|
||||
}
|
||||
|
@ -59,29 +56,24 @@ function mcl_loot.get_loot(loot_definitions, pr)
|
|||
end
|
||||
if item then
|
||||
local itemstring = item.itemstring
|
||||
local itemstack = item.itemstack
|
||||
if itemstring then
|
||||
if item.amount_min and item.amount_max then
|
||||
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max)
|
||||
end
|
||||
if item.wear_min and item.wear_max then
|
||||
-- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10
|
||||
local wear_min = math.floor(item.wear_min / 10)
|
||||
local wear_max = math.floor(item.wear_max / 10)
|
||||
local wear = pr:next(wear_min, wear_max) * 10
|
||||
|
||||
if not item.amount_min and not item.amount_max then
|
||||
itemstring = itemstring .. " 1"
|
||||
end
|
||||
|
||||
itemstring = itemstring .. " " .. tostring(wear)
|
||||
end
|
||||
table.insert(items, itemstring)
|
||||
elseif itemstack then
|
||||
table.insert(items, itemstack)
|
||||
else
|
||||
minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!")
|
||||
if item.amount_min and item.amount_max then
|
||||
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max)
|
||||
end
|
||||
if item.wear_min and item.wear_max then
|
||||
-- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10
|
||||
local wear_min = math.floor(item.wear_min / 10)
|
||||
local wear_max = math.floor(item.wear_max / 10)
|
||||
local wear = pr:next(wear_min, wear_max) * 10
|
||||
|
||||
if not item.amount_min and not item.amount_max then
|
||||
itemstring = itemstring .. " 1"
|
||||
end
|
||||
|
||||
itemstring = itemstring .. " " .. tostring(wear)
|
||||
end
|
||||
table.insert(items, itemstring)
|
||||
else
|
||||
minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -111,14 +103,14 @@ end
|
|||
Returns a table of length `max_slot` and all natural numbers between 1 and `max_slot`
|
||||
in a random order.
|
||||
]]
|
||||
local function get_random_slots(max_slot, pr)
|
||||
local function get_random_slots(max_slot)
|
||||
local slots = {}
|
||||
for s=1, max_slot do
|
||||
slots[s] = s
|
||||
end
|
||||
local slots_out = {}
|
||||
while #slots > 0 do
|
||||
local r = pr and pr:next(1, #slots) or math.random(1, #slots)
|
||||
local r = math.random(1, #slots)
|
||||
table.insert(slots_out, slots[r])
|
||||
table.remove(slots, r)
|
||||
end
|
||||
|
@ -135,9 +127,9 @@ Items will be added from start of the table to end.
|
|||
If the inventory already has occupied slots, or is
|
||||
too small, placement of some items might fail.
|
||||
]]
|
||||
function mcl_loot.fill_inventory(inv, listname, items, pr)
|
||||
function mcl_loot.fill_inventory(inv, listname, items)
|
||||
local size = inv:get_size(listname)
|
||||
local slots = get_random_slots(size, pr)
|
||||
local slots = get_random_slots(size)
|
||||
local leftovers = {}
|
||||
-- 1st pass: Add items into random slots
|
||||
for i=1, math.min(#items, size) do
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
mcl_particles = {}
|
||||
|
||||
-- Table of particlespawner IDs on a per-node hash basis
|
||||
-- Keys: node position hashes
|
||||
-- Values: Tables of particlespawner IDs (each node pos can have an arbitrary number of particlespawners)
|
||||
local particle_nodes = {}
|
||||
|
||||
-- Node particles can be disabled via setting
|
||||
local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none"
|
||||
|
||||
local levels = {
|
||||
high = 3,
|
||||
medium = 2,
|
||||
low = 1,
|
||||
none = 0,
|
||||
}
|
||||
|
||||
allowed_level = levels[node_particles_allowed]
|
||||
if not allowed_level then
|
||||
allowed_level = levels["none"]
|
||||
end
|
||||
|
||||
|
||||
-- Add a particlespawner that is assigned to a given node position.
|
||||
-- * pos: Node positon. MUST use integer values!
|
||||
-- * particlespawner_definition: definition for minetest.add_particlespawner
|
||||
-- * level: detail level of particles. "high", "medium", "low" or "none". High detail levels are for
|
||||
-- CPU-demanding particles, like smoke of fire (which occurs frequently)
|
||||
-- NOTE: All particlespawners are automatically removed on shutdown.
|
||||
-- Returns particlespawner ID on succcess and nil on failure
|
||||
function mcl_particles.add_node_particlespawner(pos, particlespawner_definition, level)
|
||||
if allowed_level == 0 or levels[level] > allowed_level then
|
||||
return
|
||||
end
|
||||
local poshash = minetest.hash_node_position(pos)
|
||||
if not poshash then
|
||||
return
|
||||
end
|
||||
local id = minetest.add_particlespawner(particlespawner_definition)
|
||||
if id == -1 then
|
||||
return
|
||||
end
|
||||
if not particle_nodes[poshash] then
|
||||
particle_nodes[poshash] = {}
|
||||
end
|
||||
table.insert(particle_nodes[poshash], id)
|
||||
return id
|
||||
end
|
||||
|
||||
-- Deletes all particlespawners that are assigned to a node position.
|
||||
-- If no particlespawners exist for this position, nothing happens.
|
||||
-- pos: Node positon. MUST use integer values!
|
||||
-- Returns true if particlespawner could be removed and false if not
|
||||
function mcl_particles.delete_node_particlespawners(pos)
|
||||
if allowed_level == 0 then
|
||||
return false
|
||||
end
|
||||
local poshash = minetest.hash_node_position(pos)
|
||||
local ids = particle_nodes[poshash]
|
||||
if ids then
|
||||
for i=1, #ids do
|
||||
minetest.delete_particlespawner(ids[i])
|
||||
end
|
||||
particle_nodes[poshash] = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
Before Width: | Height: | Size: 126 B After Width: | Height: | Size: 938 B |
Before Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 91 B |
Before Width: | Height: | Size: 137 B |
Before Width: | Height: | Size: 145 B |
Before Width: | Height: | Size: 125 B |
Before Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 262 B |
Before Width: | Height: | Size: 126 B |
Before Width: | Height: | Size: 126 B |
Before Width: | Height: | Size: 216 B |
|
@ -114,9 +114,9 @@ end
|
|||
function mcl_sounds.node_sound_leaves_defaults(table)
|
||||
table = table or {}
|
||||
table.footstep = table.footstep or
|
||||
{name="default_grass_footstep", gain=0.1325}
|
||||
{name="default_grass_footstep", gain=0.35}
|
||||
table.dug = table.dug or
|
||||
{name="default_grass_footstep", gain=0.425}
|
||||
{name="default_grass_footstep", gain=0.85}
|
||||
table.dig = table.dig or
|
||||
{name="default_dig_snappy", gain=0.4}
|
||||
table.place = table.place or
|
||||
|
|
|
@ -395,13 +395,4 @@ function mcl_util.generate_on_place_plant_function(condition)
|
|||
end
|
||||
end
|
||||
|
||||
-- adjust the y level of an object to the center of its collisionbox
|
||||
-- used to get the origin position of entity explosions
|
||||
function mcl_util.get_object_center(obj)
|
||||
local collisionbox = obj:get_properties().collisionbox
|
||||
local pos = obj:get_pos()
|
||||
local ymin = collisionbox[2]
|
||||
local ymax = collisionbox[5]
|
||||
pos.y = pos.y + (ymax - ymin) / 2.0
|
||||
return pos
|
||||
end
|
||||
|
||||
|
|
|
@ -70,12 +70,6 @@ function mcl_worlds.has_weather(pos)
|
|||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||
end
|
||||
|
||||
-- Takes a position and returns true if this position can have Nether dust
|
||||
function mcl_worlds.has_dust(pos)
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= mcl_vars.mg_nether_max + 64 and pos.y >= mcl_vars.mg_nether_min - 64
|
||||
end
|
||||
|
||||
-- Takes a position (pos) and returns true if compasses are working here
|
||||
function mcl_worlds.compass_works(pos)
|
||||
-- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
-- register extra flavours of a base nodedef
|
||||
walkover = {}
|
||||
walkover.registered_globals = {}
|
||||
|
||||
function walkover.register_global(func)
|
||||
table.insert(walkover.registered_globals, func)
|
||||
end
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime;
|
||||
|
@ -17,15 +10,11 @@ minetest.register_globalstep(function(dtime)
|
|||
if loc ~= nil then
|
||||
|
||||
local nodeiamon = minetest.get_node(loc)
|
||||
|
||||
if nodeiamon ~= nil then
|
||||
local def = minetest.registered_nodes[nodeiamon.name]
|
||||
if def ~= nil and def.on_walk_over ~= nil then
|
||||
def.on_walk_over(loc, nodeiamon, player)
|
||||
end
|
||||
for _, func in ipairs(walkover.registered_globals) do
|
||||
func(loc, nodeiamon, player)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,24 +1,13 @@
|
|||
local S = minetest.get_translator("mcl_boats")
|
||||
|
||||
local boat_visual_size = {x = 3, y = 3, z = 3}
|
||||
local paddling_speed = 22
|
||||
local boat_y_offset = 0.35
|
||||
local boat_y_offset_ground = boat_y_offset + 0.6
|
||||
local boat_side_offset = 1.001
|
||||
local boat_max_hp = 4
|
||||
|
||||
local function is_group(pos, group)
|
||||
local nn = minetest.get_node(pos).name
|
||||
return minetest.get_item_group(nn, group) ~= 0
|
||||
end
|
||||
--
|
||||
-- Helper functions
|
||||
--
|
||||
|
||||
local function is_water(pos)
|
||||
return is_group(pos, "water")
|
||||
local nn = minetest.get_node(pos).name
|
||||
return minetest.get_item_group(nn, "water") ~= 0
|
||||
end
|
||||
|
||||
local function is_ice(pos)
|
||||
return is_group(pos, "ice")
|
||||
end
|
||||
|
||||
local function get_sign(i)
|
||||
if i == 0 then
|
||||
|
@ -28,83 +17,25 @@ local function get_sign(i)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
local function get_velocity(v, yaw, y)
|
||||
local x = -math.sin(yaw) * v
|
||||
local z = math.cos(yaw) * v
|
||||
return {x = x, y = y, z = z}
|
||||
end
|
||||
|
||||
|
||||
local function get_v(v)
|
||||
return math.sqrt(v.x ^ 2 + v.z ^ 2)
|
||||
end
|
||||
|
||||
local function check_object(obj)
|
||||
return obj and (obj:is_player() or obj:get_luaentity()) and obj
|
||||
end
|
||||
|
||||
local function get_visual_size(obj)
|
||||
return obj:is_player() and {x = 1, y = 1, z = 1} or obj:get_luaentity()._old_visual_size or obj:get_properties().visual_size
|
||||
end
|
||||
|
||||
local function set_attach(boat)
|
||||
boat._driver:set_attach(boat.object, "",
|
||||
{x = 0, y = 0.42, z = -1}, {x = 0, y = 0, z = 0})
|
||||
end
|
||||
|
||||
local function set_double_attach(boat)
|
||||
boat._driver:set_attach(boat.object, "",
|
||||
{x = 0, y = 0.42, z = 0.8}, {x = 0, y = 0, z = 0})
|
||||
boat._passenger:set_attach(boat.object, "",
|
||||
{x = 0, y = 0.42, z = -2.2}, {x = 0, y = 0, z = 0})
|
||||
end
|
||||
|
||||
local function attach_object(self, obj)
|
||||
if self._driver then
|
||||
if self._driver:is_player() then
|
||||
self._passenger = obj
|
||||
else
|
||||
self._passenger = self._driver
|
||||
self._driver = obj
|
||||
end
|
||||
set_double_attach(self)
|
||||
else
|
||||
self._driver = obj
|
||||
set_attach(self)
|
||||
end
|
||||
|
||||
local visual_size = get_visual_size(obj)
|
||||
local yaw = self.object:get_yaw()
|
||||
obj:set_properties({visual_size = vector.divide(visual_size, boat_visual_size)})
|
||||
|
||||
if obj:is_player() then
|
||||
local name = obj:get_player_name()
|
||||
mcl_player.player_attached[name] = true
|
||||
minetest.after(0.2, function(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player then
|
||||
mcl_player.player_set_animation(player, "sit" , 30)
|
||||
end
|
||||
end, name)
|
||||
obj:set_look_horizontal(yaw)
|
||||
mcl_tmp_message.message(obj, S("Sneak to dismount"))
|
||||
else
|
||||
obj:get_luaentity()._old_visual_size = visual_size
|
||||
end
|
||||
end
|
||||
|
||||
local function detach_object(obj, change_pos)
|
||||
obj:set_detach()
|
||||
obj:set_properties({visual_size = get_visual_size(obj)})
|
||||
if obj:is_player() then
|
||||
mcl_player.player_attached[obj:get_player_name()] = false
|
||||
mcl_player.player_set_animation(obj, "stand" , 30)
|
||||
else
|
||||
obj:get_luaentity()._old_visual_size = nil
|
||||
end
|
||||
if change_pos then
|
||||
obj:set_pos(vector.add(obj:get_pos(), vector.new(0, 0.2, 0)))
|
||||
end
|
||||
end
|
||||
local boat_visual_size = {x = 3, y = 3}
|
||||
-- Note: This mod assumes the default player visual_size is {x=1, y=1}
|
||||
local driver_visual_size = { x = 1/boat_visual_size.x, y = 1/boat_visual_size.y }
|
||||
local paddling_speed = 22
|
||||
local boat_y_offset = 0.35
|
||||
local boat_y_offset_ground = boat_y_offset + 0.6
|
||||
local boat_side_offset = 1.001
|
||||
|
||||
--
|
||||
-- Boat entity
|
||||
|
@ -119,41 +50,67 @@ local boat = {
|
|||
mesh = "mcl_boats_boat.b3d",
|
||||
textures = {"mcl_boats_texture_oak_boat.png"},
|
||||
visual_size = boat_visual_size,
|
||||
hp_max = boat_max_hp,
|
||||
damage_texture_modifier = "^[colorize:white:0",
|
||||
|
||||
_driver = nil, -- Attached driver (player) or nil if none
|
||||
_passenger = nil,
|
||||
_v = 0, -- Speed
|
||||
_last_v = 0, -- Temporary speed variable
|
||||
_removed = false, -- If true, boat entity is considered removed (e.g. after punch) and should be ignored
|
||||
_itemstring = "mcl_boats:boat", -- Itemstring of the boat item (implies boat type)
|
||||
_animation = 0, -- 0: not animated; 1: paddling forwards; -1: paddling forwards
|
||||
_regen_timer = 0,
|
||||
_damage_anim = 0,
|
||||
}
|
||||
|
||||
minetest.register_on_respawnplayer(detach_object)
|
||||
|
||||
function boat.on_rightclick(self, clicker)
|
||||
if self._passenger or not clicker or clicker:get_attach() then
|
||||
if not clicker or not clicker:is_player() then
|
||||
return
|
||||
end
|
||||
attach_object(self, clicker)
|
||||
local name = clicker:get_player_name()
|
||||
if self._driver and clicker == self._driver then
|
||||
self._driver = nil
|
||||
clicker:set_detach()
|
||||
clicker:set_properties({visual_size = {x=1, y=1}})
|
||||
mcl_player.player_attached[name] = false
|
||||
mcl_player.player_set_animation(clicker, "stand" , 30)
|
||||
local pos = clicker:get_pos()
|
||||
pos = {x = pos.x, y = pos.y + 0.2, z = pos.z}
|
||||
clicker:set_pos(pos)
|
||||
elseif not self._driver then
|
||||
local attach = clicker:get_attach()
|
||||
if attach and attach:get_luaentity() then
|
||||
local luaentity = attach:get_luaentity()
|
||||
if luaentity._driver then
|
||||
luaentity._driver = nil
|
||||
end
|
||||
clicker:set_detach()
|
||||
clicker:set_properties({visual_size = {x=1, y=1}})
|
||||
end
|
||||
self._driver = clicker
|
||||
clicker:set_attach(self.object, "",
|
||||
{x = 0, y = 0.42, z = -1}, {x = 0, y = 0, z = 0})
|
||||
clicker:set_properties({ visual_size = driver_visual_size })
|
||||
mcl_player.player_attached[name] = true
|
||||
minetest.after(0.2, function(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player then
|
||||
mcl_player.player_set_animation(player, "sit" , 30)
|
||||
end
|
||||
end, name)
|
||||
clicker:set_look_horizontal(self.object:get_yaw())
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function boat.on_activate(self, staticdata, dtime_s)
|
||||
self.object:set_armor_groups({fleshy = 100})
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
local data = minetest.deserialize(staticdata)
|
||||
if type(data) == "table" then
|
||||
self._v = data.v
|
||||
self._last_v = self._v
|
||||
self._itemstring = data.itemstring
|
||||
self.object:set_properties({textures = data.textures})
|
||||
self.object:set_properties({textures=data.textures})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function boat.get_staticdata(self)
|
||||
return minetest.serialize({
|
||||
v = self._v,
|
||||
|
@ -162,104 +119,52 @@ function boat.get_staticdata(self)
|
|||
})
|
||||
end
|
||||
|
||||
function boat.on_death(self, killer)
|
||||
if killer and killer:is_player() and minetest.is_creative_enabled(killer:get_player_name()) then
|
||||
local inv = killer:get_inventory()
|
||||
if not inv:contains_item("main", self._itemstring) then
|
||||
inv:add_item("main", self._itemstring)
|
||||
|
||||
function boat.on_punch(self, puncher)
|
||||
if not puncher or not puncher:is_player() or self._removed then
|
||||
return
|
||||
end
|
||||
if self._driver and puncher == self._driver then
|
||||
self._driver = nil
|
||||
puncher:set_detach()
|
||||
puncher:set_properties({visual_size = {x=1, y=1}})
|
||||
mcl_player.player_attached[puncher:get_player_name()] = false
|
||||
end
|
||||
if not self._driver then
|
||||
self._removed = true
|
||||
-- Drop boat as item on the ground after punching
|
||||
if not minetest.is_creative_enabled(puncher:get_player_name()) then
|
||||
minetest.add_item(self.object:get_pos(), self._itemstring)
|
||||
else
|
||||
local inv = puncher:get_inventory()
|
||||
if not inv:contains_item("main", self._itemstring) then
|
||||
inv:add_item("main", self._itemstring)
|
||||
end
|
||||
end
|
||||
else
|
||||
minetest.add_item(self.object:get_pos(), self._itemstring)
|
||||
end
|
||||
if self._driver then
|
||||
detach_object(self._driver)
|
||||
end
|
||||
if self._passenger then
|
||||
detach_object(self._passenger)
|
||||
end
|
||||
self._driver = nil
|
||||
self._passenger = nil
|
||||
end
|
||||
|
||||
function boat.on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
||||
if damage > 0 then
|
||||
self._regen_timer = 0
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
|
||||
function boat.on_step(self, dtime, moveresult)
|
||||
function boat.on_step(self, dtime)
|
||||
self._v = get_v(self.object:get_velocity()) * get_sign(self._v)
|
||||
local on_water = true
|
||||
local in_water = false
|
||||
local v_factor = 1
|
||||
local v_slowdown = 0.02
|
||||
local p = self.object:get_pos()
|
||||
local on_water = true
|
||||
local on_ice = false
|
||||
local in_water = is_water({x=p.x, y=p.y-boat_y_offset+1, z=p.z})
|
||||
local waterp = {x=p.x, y=p.y-boat_y_offset - 0.1, z=p.z}
|
||||
if not is_water(waterp) then
|
||||
if (not is_water({x=p.x, y=p.y-boat_y_offset, z=p.z})) then
|
||||
on_water = false
|
||||
if not in_water and is_ice(waterp) then
|
||||
on_ice = true
|
||||
else
|
||||
v_slowdown = 0.04
|
||||
end
|
||||
|
||||
v_factor = 0.5
|
||||
elseif in_water then
|
||||
v_slowdown = 0.04
|
||||
elseif (is_water({x=p.x, y=p.y-boat_y_offset+1, z=p.z})) then
|
||||
on_water = false
|
||||
in_water = true
|
||||
v_factor = 0.75
|
||||
v_slowdown = 0.05
|
||||
end
|
||||
|
||||
local hp = self.object:get_hp()
|
||||
local regen_timer = self._regen_timer + dtime
|
||||
if hp >= boat_max_hp then
|
||||
regen_timer = 0
|
||||
elseif regen_timer >= 0.5 then
|
||||
hp = hp + 1
|
||||
self.object:set_hp(hp)
|
||||
regen_timer = 0
|
||||
end
|
||||
self._regen_timer = regen_timer
|
||||
|
||||
if moveresult and moveresult.collides then
|
||||
for _, collision in ipairs(moveresult.collisions) do
|
||||
local pos = collision.node_pos
|
||||
if collision.type == "node" and minetest.get_item_group(minetest.get_node(pos).name, "dig_by_boat") > 0 then
|
||||
minetest.dig_node(pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local had_passenger = self._passenger
|
||||
|
||||
self._driver = check_object(self._driver)
|
||||
self._passenger = check_object(self._passenger)
|
||||
|
||||
if self._passenger then
|
||||
if not self._driver then
|
||||
self._driver = self._passenger
|
||||
self._passenger = nil
|
||||
else
|
||||
local ctrl = self._passenger:get_player_control()
|
||||
if ctrl and ctrl.sneak then
|
||||
detach_player(self._passenger, true)
|
||||
self._passenger = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self._driver then
|
||||
if had_passenger and not self._passenger then
|
||||
set_attach(self)
|
||||
end
|
||||
local ctrl = self._driver:get_player_control()
|
||||
if ctrl and ctrl.sneak then
|
||||
detach_object(self._driver, true)
|
||||
self._driver = nil
|
||||
return
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
if ctrl.up then
|
||||
-- Forwards
|
||||
|
@ -286,13 +191,13 @@ function boat.on_step(self, dtime, moveresult)
|
|||
self._animation = 0
|
||||
end
|
||||
end
|
||||
if ctrl and ctrl.left then
|
||||
if ctrl.left then
|
||||
if self._v < 0 then
|
||||
self.object:set_yaw(yaw - (1 + dtime) * 0.03 * v_factor)
|
||||
else
|
||||
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
||||
end
|
||||
elseif ctrl and ctrl.right then
|
||||
elseif ctrl.right then
|
||||
if self._v < 0 then
|
||||
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
||||
else
|
||||
|
@ -305,19 +210,11 @@ function boat.on_step(self, dtime, moveresult)
|
|||
self.object:set_animation({x=0, y=40}, 0, 0, true)
|
||||
self._animation = 0
|
||||
end
|
||||
|
||||
for _, obj in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 1.3)) do
|
||||
local entity = obj:get_luaentity()
|
||||
if entity and entity._cmi_is_mob then
|
||||
attach_object(self, obj)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local s = get_sign(self._v)
|
||||
if not on_ice and not on_water and not in_water and math.abs(self._v) > 2.0 then
|
||||
v_slowdown = math.min(math.abs(self._v) - 2.0, v_slowdown * 5)
|
||||
elseif not on_ice and in_water and math.abs(self._v) > 1.5 then
|
||||
if not on_water and not in_water and math.abs(self._v) > 1.0 then
|
||||
v_slowdown = math.min(math.abs(self._v) - 1.0, v_slowdown * 5)
|
||||
elseif in_water and math.abs(self._v) > 1.5 then
|
||||
v_slowdown = math.min(math.abs(self._v) - 1.5, v_slowdown * 5)
|
||||
end
|
||||
self._v = self._v - v_slowdown * s
|
||||
|
@ -328,7 +225,7 @@ function boat.on_step(self, dtime, moveresult)
|
|||
p.y = p.y - boat_y_offset
|
||||
local new_velo
|
||||
local new_acce = {x = 0, y = 0, z = 0}
|
||||
if not is_water(p) and not on_ice then
|
||||
if not is_water(p) then
|
||||
-- Not on water or inside water: Free fall
|
||||
local nodedef = minetest.registered_nodes[minetest.get_node(p).name]
|
||||
new_acce = {x = 0, y = -9.8, z = 0}
|
||||
|
@ -358,17 +255,12 @@ function boat.on_step(self, dtime, moveresult)
|
|||
end
|
||||
|
||||
-- Terminal velocity: 8 m/s per axis of travel
|
||||
local terminal_velocity = on_ice and 57.1 or 8.0
|
||||
for _,axis in pairs({"z","y","x"}) do
|
||||
if math.abs(new_velo[axis]) > terminal_velocity then
|
||||
new_velo[axis] = terminal_velocity * get_sign(new_velo[axis])
|
||||
if math.abs(new_velo[axis]) > 8 then
|
||||
new_velo[axis] = 8 * get_sign(new_velo[axis])
|
||||
end
|
||||
end
|
||||
|
||||
local yaw = self.object:get_yaw()
|
||||
local anim = (boat_max_hp - hp - regen_timer * 2) / boat_max_hp * math.pi / 4
|
||||
|
||||
self.object:set_rotation(vector.new(anim, yaw, anim))
|
||||
self.object:set_velocity(new_velo)
|
||||
self.object:set_acceleration(new_acce)
|
||||
end
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# textdomain: mcl_boats
|
||||
Acacia Boat=Лодка из акации
|
||||
Birch Boat=Берёзовая лодка
|
||||
Boat=Лодка
|
||||
Boats are used to travel on the surface of water.=С помощью лодки можно путешествовать по водной поверхности.
|
||||
Dark Oak Boat=Лодка из тёмного дуба
|
||||
Jungle Boat=Лодка из дерева джунглей
|
||||
Oak Boat=Дубовая лодка
|
||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.=Правый клик по воде спустит лодку на воду. Правый клик по лодке разместит вас в ней. [Влево] и [Вправо] - рулить, [Вперед] - разгоняться, [Назад] - тормозить или плыть назад. Правый клик по лодке, когда вы в ней, позволит выйти из неё. Удар по лодке превратит её обратно в предмет.
|
||||
Spruce Boat=Еловая лодка
|
||||
Water vehicle=Водный транспорт
|
|
@ -1,298 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_burning")
|
||||
|
||||
function mcl_burning.get_default(datatype)
|
||||
local default_table = {string = "", float = 0.0, int = 0, bool = false}
|
||||
return default_table[datatype]
|
||||
end
|
||||
|
||||
function mcl_burning.get(obj, datatype, name)
|
||||
local key
|
||||
if obj:is_player() then
|
||||
local meta = obj:get_meta()
|
||||
return meta["get_" .. datatype](meta, "mcl_burning:" .. name)
|
||||
else
|
||||
local luaentity = obj:get_luaentity()
|
||||
return luaentity and luaentity["mcl_burning_" .. name] or mcl_burning.get_default(datatype)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.set(obj, datatype, name, value)
|
||||
if obj:is_player() then
|
||||
local meta = obj:get_meta()
|
||||
meta["set_" .. datatype](meta, "mcl_burning:" .. name, value or mcl_burning.get_default(datatype))
|
||||
else
|
||||
local luaentity = obj:get_luaentity()
|
||||
if mcl_burning.get_default(datatype) == value then
|
||||
value = nil
|
||||
end
|
||||
luaentity["mcl_burning_" .. name] = value
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.is_burning(obj)
|
||||
return mcl_burning.get(obj, "float", "burn_time") > 0
|
||||
end
|
||||
|
||||
function mcl_burning.is_affected_by_rain(obj)
|
||||
return mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos())
|
||||
end
|
||||
|
||||
function mcl_burning.get_collisionbox(obj, smaller)
|
||||
local box = obj:get_properties().collisionbox
|
||||
local minp, maxp = vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6])
|
||||
if smaller then
|
||||
local s_vec = vector.new(0.1, 0.1, 0.1)
|
||||
minp = vector.add(minp, s_vec)
|
||||
maxp = vector.subtract(maxp, s_vec)
|
||||
end
|
||||
return minp, maxp
|
||||
end
|
||||
|
||||
function mcl_burning.get_touching_nodes(obj, nodenames)
|
||||
local pos = obj:get_pos()
|
||||
local box = obj:get_properties().collisionbox
|
||||
local minp, maxp = mcl_burning.get_collisionbox(obj, true)
|
||||
local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
||||
return nodes
|
||||
end
|
||||
|
||||
function mcl_burning.get_highest_group_value(obj, groupname)
|
||||
local nodes = mcl_burning.get_touching_nodes(obj, "group:" .. groupname, true)
|
||||
local highest_group_value = 0
|
||||
|
||||
for _, pos in pairs(nodes) do
|
||||
local node = minetest.get_node(pos)
|
||||
local group_value = minetest.get_item_group(node.name, groupname)
|
||||
if group_value > highest_group_value then
|
||||
highest_group_value = group_value
|
||||
end
|
||||
end
|
||||
|
||||
return highest_group_value
|
||||
end
|
||||
|
||||
function mcl_burning.damage(obj)
|
||||
local luaentity = obj:get_luaentity()
|
||||
local health
|
||||
|
||||
if luaentity then
|
||||
health = luaentity.health
|
||||
end
|
||||
|
||||
local hp = health or obj:get_hp()
|
||||
|
||||
if hp <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local do_damage = true
|
||||
|
||||
if obj:is_player() then
|
||||
if mcl_potions.player_has_effect(obj, "fire_proof") then
|
||||
do_damage = false
|
||||
else
|
||||
local name = obj:get_player_name()
|
||||
armor.last_damage_types[name] = "fire"
|
||||
local deathmsg = S("@1 burned to death.", name)
|
||||
local reason = mcl_burning.get(obj, "string", "reason")
|
||||
if reason ~= "" then
|
||||
deathmsg = S("@1 was burned by @2.", name, reason)
|
||||
end
|
||||
mcl_death_messages.player_damage(obj, deathmsg)
|
||||
end
|
||||
else
|
||||
if luaentity.fire_damage_resistant then
|
||||
do_damage = false
|
||||
end
|
||||
end
|
||||
|
||||
if do_damage then
|
||||
local new_hp = hp - 1
|
||||
if health then
|
||||
luaentity.health = new_hp
|
||||
else
|
||||
obj:set_hp(new_hp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.set_on_fire(obj, burn_time, reason)
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity and luaentity.fire_resistant then
|
||||
return
|
||||
end
|
||||
|
||||
local old_burn_time = mcl_burning.get(obj, "float", "burn_time")
|
||||
local max_fire_prot_lvl = 0
|
||||
|
||||
if obj:is_player() then
|
||||
if minetest.is_creative_enabled(obj:get_player_name()) then
|
||||
burn_time = burn_time / 100
|
||||
end
|
||||
|
||||
local inv = obj:get_inventory()
|
||||
|
||||
for i = 2, 5 do
|
||||
local stack = inv:get_stack("armor", i)
|
||||
|
||||
local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
|
||||
max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl)
|
||||
end
|
||||
end
|
||||
|
||||
if max_fire_prot_lvl > 0 then
|
||||
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
||||
end
|
||||
|
||||
if old_burn_time <= burn_time then
|
||||
local sound_id = mcl_burning.get(obj, "int", "sound_id")
|
||||
if sound_id == 0 then
|
||||
sound_id = minetest.sound_play("fire_fire", {
|
||||
object = obj,
|
||||
gain = 0.18,
|
||||
max_hear_distance = 16,
|
||||
loop = true,
|
||||
}) + 1
|
||||
end
|
||||
|
||||
local hud_id
|
||||
if obj:is_player() then
|
||||
hud_id = mcl_burning.get(obj, "int", "hud_id")
|
||||
if hud_id == 0 then
|
||||
hud_id = obj:hud_add({
|
||||
hud_elem_type = "image",
|
||||
position = {x = 0.5, y = 0.5},
|
||||
scale = {x = -100, y = -100},
|
||||
text = "fire_basic_flame.png",
|
||||
z_index = 1000,
|
||||
}) + 1
|
||||
end
|
||||
end
|
||||
mcl_burning.set(obj, "float", "burn_time", burn_time)
|
||||
mcl_burning.set(obj, "string", "reason", reason)
|
||||
mcl_burning.set(obj, "int", "hud_id", hud_id)
|
||||
mcl_burning.set(obj, "int", "sound_id", sound_id)
|
||||
|
||||
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||
local minp, maxp = mcl_burning.get_collisionbox(obj)
|
||||
local obj_size = obj:get_properties().visual_size
|
||||
|
||||
local vertical_grow_factor = 1.2
|
||||
local horizontal_grow_factor = 1.1
|
||||
local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor)
|
||||
|
||||
local size = vector.subtract(maxp, minp)
|
||||
size = vector.multiply(size, grow_vector)
|
||||
size = vector.divide(size, obj_size)
|
||||
local offset = vector.new(0, size.y * 10 / 2, 0)
|
||||
|
||||
fire_entity:set_properties({visual_size = size})
|
||||
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0})
|
||||
mcl_burning.update_animation_frame(obj, fire_entity, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.extinguish(obj)
|
||||
if mcl_burning.is_burning(obj) then
|
||||
local sound_id = mcl_burning.get(obj, "int", "sound_id") - 1
|
||||
minetest.sound_stop(sound_id)
|
||||
|
||||
if obj:is_player() then
|
||||
local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1
|
||||
obj:hud_remove(hud_id)
|
||||
end
|
||||
|
||||
mcl_burning.set(obj, "string", "reason")
|
||||
mcl_burning.set(obj, "float", "burn_time")
|
||||
mcl_burning.set(obj, "float", "damage_timer")
|
||||
mcl_burning.set(obj, "int", "hud_id")
|
||||
mcl_burning.set(obj, "int", "sound_id")
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.catch_fire_tick(obj, dtime)
|
||||
if mcl_burning.is_affected_by_rain(obj) or #mcl_burning.get_touching_nodes(obj, "group:puts_out_fire") > 0 then
|
||||
mcl_burning.extinguish(obj)
|
||||
else
|
||||
local set_on_fire_value = mcl_burning.get_highest_group_value(obj, "set_on_fire")
|
||||
|
||||
if set_on_fire_value > 0 then
|
||||
mcl_burning.set_on_fire(obj, set_on_fire_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.tick(obj, dtime)
|
||||
local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime
|
||||
|
||||
if burn_time <= 0 then
|
||||
mcl_burning.extinguish(obj)
|
||||
else
|
||||
mcl_burning.set(obj, "float", "burn_time", burn_time)
|
||||
|
||||
local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime
|
||||
|
||||
if damage_timer >= 1 then
|
||||
damage_timer = 0
|
||||
mcl_burning.damage(obj)
|
||||
end
|
||||
|
||||
mcl_burning.set(obj, "float", "damage_timer", damage_timer)
|
||||
end
|
||||
|
||||
mcl_burning.catch_fire_tick(obj, dtime)
|
||||
end
|
||||
|
||||
function mcl_burning.update_animation_frame(obj, fire_entity, animation_frame)
|
||||
local fire_texture = "mcl_burning_entity_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. animation_frame
|
||||
local fire_HUD_texture = "mcl_burning_hud_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. animation_frame
|
||||
fire_entity:set_properties({textures = {"blank.png", "blank.png", fire_texture, fire_texture, fire_texture, fire_texture}})
|
||||
if obj:is_player() then
|
||||
local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1
|
||||
obj:hud_change(hud_id, "text", fire_HUD_texture)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.fire_entity_step(self, dtime)
|
||||
if self.removed then
|
||||
return
|
||||
end
|
||||
|
||||
local obj = self.object
|
||||
local parent = obj:get_attach()
|
||||
local do_remove
|
||||
|
||||
self.doing_step = true
|
||||
|
||||
if not parent or not mcl_burning.is_burning(parent) then
|
||||
do_remove = true
|
||||
else
|
||||
for _, other in ipairs(minetest.get_objects_inside_radius(obj:get_pos(), 0)) do
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity and luaentity.name == "mcl_burning:fire" and not luaentity.doing_step and not luaentity.removed then
|
||||
do_remove = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.doing_step = false
|
||||
|
||||
if do_remove then
|
||||
self.removed = true
|
||||
obj:remove()
|
||||
return
|
||||
end
|
||||
|
||||
local animation_timer = self.animation_timer + dtime
|
||||
if animation_timer >= 0.015 then
|
||||
animation_timer = 0
|
||||
local animation_frame = self.animation_frame + 1
|
||||
if animation_frame > mcl_burning.animation_frames - 1 then
|
||||
animation_frame = 0
|
||||
end
|
||||
mcl_burning.update_animation_frame(parent, obj, animation_frame)
|
||||
self.animation_frame = animation_frame
|
||||
end
|
||||
self.animation_timer = animation_timer
|
||||
end
|
|
@ -1,36 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_burning")
|
||||
local modpath = minetest.get_modpath("mcl_burning")
|
||||
|
||||
mcl_burning = {
|
||||
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
||||
}
|
||||
|
||||
dofile(modpath .. "/api.lua")
|
||||
|
||||
minetest.register_entity("mcl_burning:fire", {
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collisionbox = {0, 0, 0, 0, 0, 0},
|
||||
visual = "cube",
|
||||
pointable = false,
|
||||
glow = -1,
|
||||
},
|
||||
|
||||
animation_frame = 0,
|
||||
animation_timer = 0,
|
||||
on_step = mcl_burning.fire_entity_step,
|
||||
})
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
mcl_burning.tick(player, dtime)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
mcl_burning.extinguish(player)
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
mcl_burning.set(player, "int", "hud_id")
|
||||
end)
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_burning
|
||||
description = Burning Objects for MineClone2
|
||||
author = Fleckenstein
|
|
@ -1,3 +0,0 @@
|
|||
# textdomain: mcl_falling_nodes
|
||||
@1 was smashed by a falling anvil.=@1 придавило падающей наковальней.
|
||||
@1 was smashed by a falling block.=@1 раздавило падающим блоком.
|
|
@ -1,2 +1 @@
|
|||
flowlib
|
||||
mcl_enchanting
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
local item_drop_settings = {} --settings table
|
||||
item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting
|
||||
item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect!
|
||||
item_drop_settings.xp_radius_magnet = 7.25 --radius of xp magnet. MUST BE LARGER THAN radius_collect!
|
||||
item_drop_settings.radius_collect = 0.2 --radius of collection
|
||||
item_drop_settings.player_collect_height = 1.0 --added to their pos y value
|
||||
item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers
|
||||
|
@ -61,8 +60,8 @@ minetest.register_globalstep(function(dtime)
|
|||
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
|
||||
|
||||
--magnet and collection
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.radius_magnet)) do
|
||||
if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
|
||||
local collected = false
|
||||
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||
|
@ -153,11 +152,6 @@ minetest.register_globalstep(function(dtime)
|
|||
end
|
||||
end
|
||||
|
||||
elseif not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "mcl_experience:orb" then
|
||||
local entity = object:get_luaentity()
|
||||
entity.collector = player:get_player_name()
|
||||
entity.collected = true
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -194,12 +188,6 @@ local check_can_drop = function(node_name, tool_capabilities)
|
|||
if toolgroupcaps[plus] then
|
||||
return true
|
||||
end
|
||||
for e=1,5 do
|
||||
local effplus = plus .. "_efficiency_" .. e
|
||||
if toolgroupcaps[effplus] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for b=1, #basegroups do
|
||||
|
@ -211,12 +199,6 @@ local check_can_drop = function(node_name, tool_capabilities)
|
|||
if toolgroupcaps[plus] then
|
||||
return true
|
||||
end
|
||||
for e=1,5 do
|
||||
local effplus = plus .. "_efficiency_" .. e
|
||||
if toolgroupcaps[effplus] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -225,66 +207,21 @@ local check_can_drop = function(node_name, tool_capabilities)
|
|||
end
|
||||
end
|
||||
|
||||
-- Stupid workaround to get drops from a drop table:
|
||||
-- Create a temporary table in minetest.registered_nodes that contains the proper drops,
|
||||
-- because unfortunately minetest.get_node_drops needs the drop table to be inside a registered node definition
|
||||
-- (very ugly)
|
||||
|
||||
local tmp_id = 0
|
||||
|
||||
local function get_drops(drop, toolname, param2, paramtype2)
|
||||
tmp_id = tmp_id + 1
|
||||
local tmp_node_name = "mcl_item_entity:" .. tmp_id
|
||||
minetest.registered_nodes[tmp_node_name] = {
|
||||
name = tmp_node_name,
|
||||
drop = drop,
|
||||
paramtype2 = paramtype2
|
||||
}
|
||||
local drops = minetest.get_node_drops({name = tmp_node_name, param2 = param2}, toolname)
|
||||
minetest.registered_nodes[tmp_node_name] = nil
|
||||
return drops
|
||||
end
|
||||
|
||||
local function discrete_uniform_distribution(drops, min_count, max_count, cap)
|
||||
local new_drops = table.copy(drops)
|
||||
for i, item in ipairs(drops) do
|
||||
local new_item = ItemStack(item)
|
||||
local multiplier = math.random(min_count, max_count)
|
||||
if cap then
|
||||
multiplier = math.min(cap, multiplier)
|
||||
end
|
||||
new_item:set_count(multiplier * new_item:get_count())
|
||||
new_drops[i] = new_item
|
||||
end
|
||||
return new_drops
|
||||
end
|
||||
|
||||
local function get_fortune_drops(fortune_drops, fortune_level)
|
||||
local drop
|
||||
local i = fortune_level
|
||||
repeat
|
||||
drop = fortune_drops[i]
|
||||
i = i - 1
|
||||
until drop or i < 1
|
||||
return drop or {}
|
||||
end
|
||||
|
||||
function minetest.handle_node_drops(pos, drops, digger)
|
||||
-- NOTE: This function override allows digger to be nil.
|
||||
-- This means there is no digger. This is a special case which allows this function to be called
|
||||
-- by hand. Creative Mode is intentionally ignored in this case.
|
||||
|
||||
local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true)
|
||||
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
||||
if (digger ~= nil and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if node will yield its useful drop by the digger's tool
|
||||
local dug_node = minetest.get_node(pos)
|
||||
local toolcaps
|
||||
local tool
|
||||
if digger ~= nil then
|
||||
tool = digger:get_wielded_item()
|
||||
local tool = digger:get_wielded_item()
|
||||
toolcaps = tool:get_tool_capabilities()
|
||||
|
||||
if not check_can_drop(dug_node.name, toolcaps) then
|
||||
|
@ -292,16 +229,12 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
end
|
||||
end
|
||||
|
||||
--[[ Special node drops when dug by shears by reading _mcl_shears_drop or with a silk touch tool reading _mcl_silk_touch_drop
|
||||
--[[ Special node drops when dug by shears by reading _mcl_shears_drop
|
||||
from the node definition.
|
||||
Definition of _mcl_shears_drop / _mcl_silk_touch_drop:
|
||||
* true: Drop itself when dug by shears / silk touch tool
|
||||
* table: Drop every itemstring in this table when dug by shears _mcl_silk_touch_drop
|
||||
Definition of _mcl_shears_drop:
|
||||
* true: Drop itself when dug by shears
|
||||
* table: Drop every itemstring in this table when dub by shears
|
||||
]]
|
||||
|
||||
local enchantments = tool and mcl_enchanting.get_enchantments(tool, "silk_touch")
|
||||
|
||||
local silk_touch_drop = false
|
||||
local nodedef = minetest.registered_nodes[dug_node.name]
|
||||
if toolcaps ~= nil and toolcaps.groupcaps and toolcaps.groupcaps.shearsy_dig and nodedef._mcl_shears_drop then
|
||||
if nodedef._mcl_shears_drop == true then
|
||||
|
@ -309,39 +242,6 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
else
|
||||
drops = nodedef._mcl_shears_drop
|
||||
end
|
||||
elseif tool and enchantments.silk_touch and nodedef._mcl_silk_touch_drop then
|
||||
silk_touch_drop = true
|
||||
if nodedef._mcl_silk_touch_drop == true then
|
||||
drops = { dug_node.name }
|
||||
else
|
||||
drops = nodedef._mcl_silk_touch_drop
|
||||
end
|
||||
end
|
||||
|
||||
if tool and nodedef._mcl_fortune_drop and enchantments.fortune then
|
||||
local fortune_level = enchantments.fortune
|
||||
local fortune_drop = nodedef._mcl_fortune_drop
|
||||
if fortune_drop.discrete_uniform_distribution then
|
||||
local min_count = fortune_drop.min_count
|
||||
local max_count = fortune_drop.max_count + fortune_level * (fortune_drop.factor or 1)
|
||||
local chance = fortune_drop.chance or fortune_drop.get_chance and fortune_drop.get_chance(fortune_level)
|
||||
if not chance or math.random() < chance then
|
||||
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count, fortune_drop.cap)
|
||||
elseif fortune_drop.override then
|
||||
drops = {}
|
||||
end
|
||||
else
|
||||
-- Fixed Behavior
|
||||
local drop = get_fortune_drops(fortune_drop, fortune_level)
|
||||
drops = get_drops(drop, tool:get_name(), dug_node.param2, nodedef.paramtype2)
|
||||
end
|
||||
end
|
||||
|
||||
if digger and mcl_experience.throw_experience and not silk_touch_drop then
|
||||
local experience_amount = minetest.get_item_group(dug_node.name,"xp")
|
||||
if experience_amount > 0 then
|
||||
mcl_experience.throw_experience(pos, experience_amount)
|
||||
end
|
||||
end
|
||||
|
||||
for _,item in ipairs(drops) do
|
||||
|
@ -619,7 +519,6 @@ minetest.register_entity(":__builtin:item", {
|
|||
minetest.log("warning", "Item entity with empty itemstring found at "..minetest.pos_to_string(self.object:get_pos()).. "! Deleting it now.")
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
local p = self.object:get_pos()
|
||||
|
@ -645,15 +544,12 @@ minetest.register_entity(":__builtin:item", {
|
|||
local fg = minetest.get_item_group(nn, "fire")
|
||||
local dg = minetest.get_item_group(nn, "destroys_items")
|
||||
if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then
|
||||
--Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed.
|
||||
if self.age > 2 then
|
||||
if dg ~= 2 then
|
||||
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5})
|
||||
end
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
return
|
||||
if dg ~= 2 then
|
||||
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5}, true)
|
||||
end
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
-- Push item out when stuck inside solid opaque node
|
||||
|
|
|
@ -175,19 +175,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
cart.on_activate_by_rail = on_activate_by_rail
|
||||
|
||||
function cart:on_step(dtime)
|
||||
local ctrl, player = nil, nil
|
||||
if self._driver then
|
||||
player = minetest.get_player_by_name(self._driver)
|
||||
if player then
|
||||
ctrl = player:get_player_control()
|
||||
-- player detach
|
||||
if ctrl.sneak then
|
||||
detach_driver(self)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local vel = self.object:get_velocity()
|
||||
local update = {}
|
||||
if self._last_float_check == nil then
|
||||
|
@ -203,14 +190,18 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
node = minetest.get_node(rou_pos)
|
||||
local g = minetest.get_item_group(node.name, "connect_to_raillike")
|
||||
if g ~= self._railtype and self._railtype ~= nil then
|
||||
local player
|
||||
-- Detach driver
|
||||
if player then
|
||||
if self._driver then
|
||||
if self._old_pos then
|
||||
self.object:set_pos(self._old_pos)
|
||||
end
|
||||
mcl_player.player_attached[self._driver] = nil
|
||||
player:set_detach()
|
||||
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
|
||||
player = minetest.get_player_by_name(self._driver)
|
||||
if player then
|
||||
player:set_detach()
|
||||
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
|
||||
end
|
||||
end
|
||||
|
||||
-- Explode if already ignited
|
||||
|
@ -346,6 +337,14 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
end
|
||||
end
|
||||
|
||||
local ctrl, player = nil, nil
|
||||
if self._driver then
|
||||
player = minetest.get_player_by_name(self._driver)
|
||||
if player then
|
||||
ctrl = player:get_player_control()
|
||||
end
|
||||
end
|
||||
|
||||
-- Stop cart if velocity vector flips
|
||||
if self._old_vel and self._old_vel.y == 0 and
|
||||
(self._old_vel.x * vel.x < 0 or self._old_vel.z * vel.z < 0) then
|
||||
|
@ -415,17 +414,14 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
|
||||
-- Slow down or speed up
|
||||
local acc = dir.y * -1.8
|
||||
local friction = 0.4
|
||||
|
||||
local speed_mod = minetest.registered_nodes[minetest.get_node(pos).name]._rail_acceleration
|
||||
|
||||
acc = acc - friction
|
||||
|
||||
if has_fuel then
|
||||
acc = acc + 0.6
|
||||
end
|
||||
|
||||
if speed_mod and speed_mod ~= 0 then
|
||||
acc = acc + speed_mod + friction
|
||||
acc = acc + 0.2
|
||||
elseif speed_mod and speed_mod ~= 0 then
|
||||
acc = acc + speed_mod
|
||||
else
|
||||
acc = acc - 0.4
|
||||
end
|
||||
|
||||
new_acc = vector.multiply(dir, acc)
|
||||
|
@ -644,7 +640,6 @@ register_minecart(
|
|||
if player then
|
||||
mcl_player.player_set_animation(player, "sit" , 30)
|
||||
player:set_eye_offset({x=0, y=-5.5, z=0},{x=0, y=-4, z=0})
|
||||
mcl_tmp_message.message(clicker, S("Sneak to dismount"))
|
||||
end
|
||||
end, name)
|
||||
end
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
# textdomain: mcl_minecarts
|
||||
Minecart=Вагонетка
|
||||
Minecarts can be used for a quick transportion on rails.=Вагонетки нужны, чтобы быстро перемещаться по рельсам.
|
||||
Minecarts only ride on rails and always follow the tracks. At a T-junction with no straight way ahead, they turn left. The speed is affected by the rail type.=Вагонетки едут строго по проложенному железнодорожному пути. На Т-образной развилке они поворачивают налево. Скорость зависит от типа рельсов.
|
||||
You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.=Вы ставите вагонетку на рельсы. Правым кликом садитесь в неё. Стукаете, чтобы начать движение.
|
||||
To obtain the minecart, punch it while holding down the sneak key.=Чтобы взять вагонетку, стукните её, удерживая клавишу [Красться].
|
||||
A minecart with TNT is an explosive vehicle that travels on rail.=Вагон тротила это подрывной железнодорожный транспорт.
|
||||
Place it on rails. Punch it to move it. The TNT is ignited with a flint and steel or when the minecart is on an powered activator rail.=Поместите его на рельсы. Стукните, чтобы он поехал. Тротил воспламеняется, если его поджечь огнивом, либо при попадании на подключенный рельсовый активатор.
|
||||
To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited.=Чтобы взять вагон тротила, стукните его, удерживая клавишу [Красться]. Если тротил воспламенён, сделать это нельзя.
|
||||
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=Вагон с печью - это железнодорожный транспорт. Он может двигаться за счёт топлива.
|
||||
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=Поставьте его на рельсы. Если добавить немного угля, то печь зажжётся на продолжительное время и вагон сможет ехать. Стукните вагон для начала движения.
|
||||
To obtain the minecart and furnace, punch them while holding down the sneak key.=Чтобы взять вагон с печью, стукните его, удерживая клавишу [Красться].
|
||||
Minecart with Chest=Вагон с сундуком
|
||||
Minecart with Furnace=Вагон с печью
|
||||
Minecart with Command Block=Вагон с командным блоком
|
||||
Minecart with Hopper=Вагон с бункером
|
||||
Minecart with TNT=Вагон тротила
|
||||
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=Поместите на землю, чтобы сделать железную дорогу, рельсы автоматически соединятся между собой и будут превращаться в плавный повороты, T-образные развилки, перекрёстки и уклоны там, где это потребуется.
|
||||
Rail=Рельсы
|
||||
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Рельсы используются для строительства железной дороги. Обычные рельсы немного замедляют движение вагонеток из-за трения.
|
||||
Powered Rail=Подключаемые рельсы
|
||||
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Рельсы используются для строительства железной дороги. Подключённые рельсы могут разгонять и тормозить вагонетки.
|
||||
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Без энергии редстоуна рельсы будут тормозить вагонетки.
|
||||
Activator Rail=Рельсовый активатор
|
||||
Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts.=Рельсы используются для строительства железной дороги. Рельсовый активатор активирует особые вагонетки.
|
||||
To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail.=Чтобы этот блок рельсов активировал вагонетку, подключите его к энергии редстоуна и направьте вагонетку через него.
|
||||
Detector Rail=Рельсовый детектор
|
||||
Rails can be used to build transport tracks for minecarts. A detector rail is able to detect a minecart above it and powers redstone mechanisms.=Рельсы используются для строительства железной дороги. Рельсовый детектор может обнаруживать вагонетку у себя наверху и подключать механизмы редстоуна.
|
||||
To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail.=Чтобы обнаруживать вагонетку и подавать энергию редстоуна, подключите его к дорожке редстоуна или механизму редстоуна, после чего направьте любую вагонетку через него.
|
||||
Track for minecarts=Железная дорога
|
||||
Speed up when powered, slow down when not powered=Разгоняет, если подключён, тормозит, если не подключён
|
||||
Activates minecarts when powered=Активирует особые вагонетки, если подключён
|
||||
Emits redstone power when a minecart is detected=Испускает энергию редстоуна при обнаружении вагонетки
|
||||
Vehicle for fast travel on rails=Быстрый железнодорожный транспорт
|
||||
Can be ignited by tools or powered activator rail=Можно воспламенить с помощью инструмента или подключенного рельсового активатора
|
||||
Sneak to dismount=Нажмите [Красться] для высадки
|
|
@ -33,4 +33,3 @@ Activates minecarts when powered=
|
|||
Emits redstone power when a minecart is detected=
|
||||
Vehicle for fast travel on rails=
|
||||
Can be ignited by tools or powered activator rail=
|
||||
Sneak to dismount=
|
||||
|
|
|
@ -108,7 +108,6 @@ functions needed for the mob to work properly which contains the following:
|
|||
'explosion_timer' number of seconds before mob explodes while its target
|
||||
is still inside reach or explosion_damage_radius,
|
||||
defaults to 3.
|
||||
'explosiontimer_reset_radius' The distance you must travel before the timer will be reset.
|
||||
'allow_fuse_reset' Allow 'explode' attack_type to reset fuse and resume
|
||||
chasing if target leaves the blast radius or line of
|
||||
sight. Defaults to true.
|
||||
|
@ -146,14 +145,12 @@ functions needed for the mob to work properly which contains the following:
|
|||
'base_pitch' base pitch to use adult mobs, default is 1.0 (MCL2 extension)
|
||||
'random' played randomly from time to time.
|
||||
also played for overfeeding animal.
|
||||
'eat' played when mob eats something
|
||||
'war_cry' what you hear when mob starts to attack player. (currently disabled)
|
||||
'attack' what you hear when being attacked.
|
||||
'shoot_attack' sound played when mob shoots.
|
||||
'damage' sound heard when mob is hurt.
|
||||
'death' played when mob is killed.
|
||||
'jump' played when mob jumps. There's a built-in cooloff timer to avoid sound spam
|
||||
'flop' played when mob flops (like a stranded fish)
|
||||
'fuse' sound played when mob explode timer starts.
|
||||
'explode' sound played when mob explodes.
|
||||
|
||||
|
@ -225,8 +222,6 @@ functions needed for the mob to work properly which contains the following:
|
|||
|
||||
'speed_normal' is used for animation speed for compatibility with some
|
||||
older mobs.
|
||||
'pushable' Allows players, & other mobs to push the mob.
|
||||
|
||||
|
||||
|
||||
MineClone 2 extensions:
|
||||
|
@ -246,14 +241,6 @@ functions needed for the mob to work properly which contains the following:
|
|||
dir is mob's aiming direction
|
||||
'sounds_child' same as sounds, but for childs. If not defined, childs will use same
|
||||
sound as adults but with higher pitch
|
||||
'follow_velocity' The speed at which a mob moves toward the player when they're holding the appropriate follow item.
|
||||
'instant_death' If true, mob dies instantly (no death animation or delay) (default: false)
|
||||
'xp_min' the minimum XP it drops on death (default: 0)
|
||||
'xp_max' the maximum XP it drops on death (default: 0)
|
||||
'fire_resistant' If true, the mob can't burn
|
||||
'fire_damage_resistant' If true the mob will not take damage when burning
|
||||
'ignited_by_sunlight' If true the mod will burn at daytime. (Takes sunlight_damage per second)
|
||||
|
||||
|
||||
|
||||
Node Replacement
|
||||
|
@ -294,9 +281,8 @@ Custom Definition Functions
|
|||
Along with the above mob registry settings we can also use custom functions to
|
||||
enhance mob functionality and have them do many interesting things:
|
||||
|
||||
'on_die' a function that is called when the mob is killed; the
|
||||
parameters are (self, pos). Return true to skip the builtin
|
||||
death animation and death effects
|
||||
'on_die' a function that is called when the mob is killed the
|
||||
parameters are (self, pos)
|
||||
'on_rightclick' its same as in minetest.register_entity()
|
||||
'on_blast' is called when an explosion happens near mob when using TNT
|
||||
functions, parameters are (object, damage) and returns
|
||||
|
@ -353,14 +339,6 @@ for each mob.
|
|||
dogs
|
||||
'self.order' set to "follow" or "stand" so that npc will follow owner
|
||||
or stand it's ground
|
||||
'self.state' Current mob state.
|
||||
"stand": no movement (except turning around)
|
||||
"walk": walk or move around aimlessly
|
||||
"attack": chase and attack enemy
|
||||
"runaway": flee from target
|
||||
"flop": bounce around aimlessly
|
||||
(for swimming mobs that have stranded)
|
||||
"die": during death
|
||||
'self.nametag' contains the name of the mob which it can show above
|
||||
|
||||
|
||||
|
@ -431,10 +409,6 @@ This function spawns a mob as a child. The parameter mob_type is the
|
|||
entitystring of the new mob.
|
||||
This function returns the mob on success and nil otherwise.
|
||||
|
||||
mobs:death_effect(pos, collisionbox)
|
||||
|
||||
Create death particles at pos with the given collisionbox.
|
||||
|
||||
|
||||
Making Arrows
|
||||
-------------
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# textdomain: mcl_mobs
|
||||
Peaceful mode active! No monsters will spawn.=Мирный режим включён! Монстры не будут появляться.
|
||||
This allows you to place a single mob.=Позволяет вам разместить одного моба.
|
||||
Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns.=Просто поместите это туда, где хотите, чтобы появился моб. Животные будут появляться уже прирученные, если это не нужно, удерживайте клавишу [Красться] при размещении. Если поместить это на спаунер, появляющийся из него моб будет изменён.
|
||||
You need the “maphack” privilege to change the mob spawner.=Вам нужно обладать привилегией “maphack”, чтобы изменить спаунер моба.
|
||||
Name Tag=Именная бирка
|
||||
A name tag is an item to name a mob.=Именная бирка это предмет, чтобы дать мобу имя.
|
||||
Before you use the name tag, you need to set a name at an anvil. Then you can use the name tag to name a mob. This uses up the name tag.=Прежде чем использовать именную бирку, нужно задать имя на наковальне. Тогда вы сможете использовать бирку, чтобы дать имя мобу.
|
||||
Only peaceful mobs allowed!=Разрешены только мирные мобы!
|
||||
Give names to mobs=Даёт имена мобам
|
||||
Set name at anvil=Задайте имя при помощи наковальни
|
|
@ -1,3 +1,2 @@
|
|||
name = mcl_mobs
|
||||
depends = mcl_particles
|
||||
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience
|
||||
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor
|
||||
|
|
|
@ -10,14 +10,13 @@ This mod contains the API only for adding your own mobs into the world, so pleas
|
|||
|
||||
https://forum.minetest.net/viewtopic.php?f=11&t=9917
|
||||
|
||||
------------
|
||||
Credits:
|
||||
|
||||
mcl_mobs_mob_poof.ogg:
|
||||
- by Planman (license: Creative Commons Zero)
|
||||
- Source: <https://freesound.org/people/Planman/sounds/208111/>
|
||||
Items:
|
||||
|
||||
- Nametag (paper, black dye, string) can be used right-click on a tamed mob to give them a name.
|
||||
|
||||
Lucky Block items: 1
|
||||
|
||||
------------
|
||||
|
||||
Changelog from original Mobs Redo mod:
|
||||
- 1.41- Mob pathfinding has been updated thanks to Elkien3
|
||||
|
|
|
@ -143,7 +143,6 @@ minetest.register_entity("mcl_paintings:painting", {
|
|||
_xsize = 1,
|
||||
_ysize = 1,
|
||||
on_activate = function(self, staticdata)
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
if staticdata and staticdata ~= "" then
|
||||
local data = minetest.deserialize(staticdata)
|
||||
if data then
|
||||
|
@ -166,20 +165,18 @@ minetest.register_entity("mcl_paintings:painting", {
|
|||
}
|
||||
return minetest.serialize(data)
|
||||
end,
|
||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
||||
-- Drop as item on punch
|
||||
if puncher and puncher:is_player() then
|
||||
kname = puncher:get_player_name()
|
||||
on_death = function(self, killer)
|
||||
-- Drop as item on death
|
||||
local kname = ""
|
||||
if killer and killer:is_player() then
|
||||
kname = killer:get_player_name()
|
||||
end
|
||||
if not minetest.is_creative_enabled(kname) then
|
||||
local pos = self._pos
|
||||
if not pos then
|
||||
pos = self.object:get_pos()
|
||||
end
|
||||
if not minetest.is_protected(pos, kname) then
|
||||
self.object:remove()
|
||||
if not minetest.is_creative_enabled(kname) then
|
||||
minetest.add_item(pos, "mcl_paintings:painting")
|
||||
end
|
||||
end
|
||||
minetest.add_item(pos, "mcl_paintings:painting")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
# textdomain:mcl_paintings
|
||||
Painting=Peinture
|
|
@ -1,2 +0,0 @@
|
|||
# textdomain:mcl_paintings
|
||||
Painting=Рисование
|
|
@ -39,7 +39,6 @@ minetest.register_node("mobs_mc:arrow_box", {
|
|||
}
|
||||
},
|
||||
tiles = {"mcl_bows_arrow.png^[transformFX", "mcl_bows_arrow.png^[transformFX", "mcl_bows_arrow_back.png", "mcl_bows_arrow_front.png", "mcl_bows_arrow.png", "mcl_bows_arrow.png^[transformFX"},
|
||||
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
|
|
|
@ -1,20 +1,11 @@
|
|||
local function is_forbidden_node(pos, node)
|
||||
node = node or minetest.get_node(pos)
|
||||
return minetest.get_item_group(node.name, "stair") > 0 or minetest.get_item_group(node.name, "slab") > 0 or minetest.get_item_group(node.name, "carpet") > 0
|
||||
end
|
||||
|
||||
function mobs:spawn_abm_check(pos, node, name)
|
||||
-- Don't spawn monsters on mycelium
|
||||
if (node.name == "mcl_core:mycelium" or node.name == "mcl_core:mycelium_snow") and minetest.registered_entities[name].type == "monster" then
|
||||
return true
|
||||
--Don't Spawn mobs on stairs, slabs, or carpets
|
||||
elseif is_forbidden_node(pos, node) or is_forbidden_node(vector.add(pos, vector.new(0, 1, 0))) then
|
||||
return true
|
||||
-- Spawn on opaque or liquid nodes
|
||||
elseif minetest.get_item_group(node.name, "opaque") ~= 0 or minetest.registered_nodes[node.name].liquidtype ~= "none" or node.name == "mcl_core:grass_path" then
|
||||
elseif minetest.get_item_group(node.name, "opaque") ~= 0 or minetest.registered_nodes[node.name].liquidtype ~= "none" then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Reject everything else
|
||||
return true
|
||||
end
|
||||
|
|
|
@ -84,12 +84,6 @@ Origin of those models:
|
|||
* [AGFX](http://www.freesound.org/people/DrMinky/sounds/) (CC0)
|
||||
* `mobs_mc_chicken_child.ogg`
|
||||
* Source: <https://freesound.org/people/AGFX/sounds/43380/>
|
||||
* [evsecrets](https://freesound.org/people/evsecrets/sounds/) (CC0)
|
||||
* `mobs_mc_chicken_*.ogg`
|
||||
* Source: <https://freesound.org/people/evsecrets/sounds/346961/>
|
||||
* [contramundum](https://freesound.org/people/contramundum/sounds/)
|
||||
* `mobs_mc_parrot_*.ogg`
|
||||
* Source: <https://freesound.org/people/contramundum/sounds/388417/>
|
||||
* Randomation (CC0)
|
||||
* `green_slime_damage.ogg`
|
||||
* `green_slime_attack.ogg`
|
||||
|
@ -105,78 +99,27 @@ Origin of those models:
|
|||
* `mobs_mc_cow_hurt.ogg` (CC0)
|
||||
* Heavily modified
|
||||
* Source: <https://freesound.org/people/Bird_man/packs/16972/>
|
||||
* [Klaraschick](https://freesound.org/people/Klaraschick/)
|
||||
* `mobs_mc_cow_milk.ogg` (CC0)
|
||||
* shortened
|
||||
* Source: <https://freesound.org/people/Klaraschick/sounds/415312/>
|
||||
* [Hitrison](https://freesound.org/people/Hitrison/)
|
||||
* `mobs_mc_cow_mushroom_stew.ogg` (CC BY 3.0)
|
||||
* sound was modified
|
||||
* Source: <https://freesound.org/people/Hitrison/sounds/251411/>
|
||||
* [NPXcoot](https://github.com/NPXcoot1) (CC BY-SA 4.0)
|
||||
* `mobs_mc_ender_dragon_*`
|
||||
* [bevibeldesign](https://freesound.org/people/bevibeldesign/)
|
||||
* `mobs_mc_wither_spawn.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/bevibeldesign/sounds/366095/>
|
||||
* [rubberduck](https://opengameart.org/users/rubberduck)
|
||||
* `mobs_mc_endermite_*.ogg` (CC0)
|
||||
* `mobs_mc_zombiepig_*.ogg` (CC0)
|
||||
* `mobs_mc_enderman_teleport_*.ogg` (CC0)
|
||||
* Source 1: <https://opengameart.org/content/80-cc0-creature-sfx>
|
||||
* Source 2: <https://opengameart.org/content/80-cc0-creture-sfx-2>
|
||||
* [Soundscapes55](https://freesound.org/people/Soundscapes55/)
|
||||
* `mobs_mc_enderman_random.1.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/Soundscapes55/sounds/434973/>
|
||||
* [griffinjennings](https://freesound.org/people/griffinjennings/)
|
||||
* `mobs_mc_enderman_death.*.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_enderman_hurt.*.ogg` (CC BY 3.0)
|
||||
* Sounds were heavily modified
|
||||
* Source: <https://freesound.org/people/griffinjennings/sounds/463972/>
|
||||
* [pointparkcinema](https://freesound.org/people/pointparkcinema/)
|
||||
* `mobs_mc_guardian_random.1.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/pointparkcinema/sounds/407252/>
|
||||
* [nornalbion](https://freesound.org/people/nornalbion/)
|
||||
* `mobs_mc_guardian_random.2.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_guardian_random.3.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_guardian_hurt.*.ogg` (CC BY 3.0)
|
||||
* Sounds were modified
|
||||
* Source: <https://freesound.org/people/nornalbion/sounds/195733/>
|
||||
* [TheBuilder15](https://freesound.org/people/TheBuilder15/)
|
||||
* `mobs_mc_guardian_death.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/pointparkcinema/sounds/407252/>
|
||||
* Blender Foundation (CC BY 3.0)
|
||||
* `mobs_sheep.ogg`,
|
||||
* daufinsyd (MIT License)
|
||||
* `mobs_mc_blaze_breath.ogg`
|
||||
* `mobs_mc_blaze_died.ogg`
|
||||
* [qubodup](https://opengameart.org/content/slime-monster)
|
||||
* `mobs_mc_squid_hurt.*.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_squid_death.*.ogg` (CC BY 3.0)
|
||||
* Changes were made
|
||||
* Source: <https://opengameart.org/content/slime-monster>
|
||||
* [kyles](https://freesound.org/people/kyles/)
|
||||
* `mobs_mc_squid_flop.*.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/kyles/sounds/450830/>
|
||||
* `mobs_mc_snowman_hurt.1.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/kyles/sounds/450848/>
|
||||
* `mobs_mc_squid_hurt.ogg`
|
||||
* [thefilmbakery](https://freesound.org/people/thefilmbakery/) (CC0)
|
||||
* `mobs_mc_blaze_hurt.ogg`
|
||||
* Source: <https://freesound.org/people/thefilmbakery/sounds/137836/>
|
||||
* TenPlus1, from `mobs_monster` or `mobs_animal` mod (MIT License)
|
||||
* `mobs_chicken.ogg`
|
||||
* `mobs_fireball.ogg`
|
||||
* `mobs_mc_cat_idle.1.ogg`
|
||||
* `mobs_mc_llama.ogg`
|
||||
* `mobs_pig.ogg`
|
||||
* `mobs_pig_angry.ogg`
|
||||
* `mobs_rat.ogg`
|
||||
* `mobs_sandmonster.ogg`
|
||||
* [Daysycho](https://freesound.org/people/Darsycho/)
|
||||
* `mobs_mc_spider_hurt.*.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/Darsycho/sounds/505185/>
|
||||
* [columbia23](https://freesound.org/people/columbia23/)
|
||||
* `mobs_mc_spider_death.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_spider_random.*.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_spider_attack.*.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/columbia23/sounds/395395/>
|
||||
* `mobs_spider.ogg`
|
||||
* BrandonReese (LGPL v2.1)
|
||||
* `mobs_eerie.ogg`
|
||||
* [Under7dude](https://freesound.org/people/Under7dude/) (CC0)
|
||||
|
@ -204,13 +147,6 @@ Origin of those models:
|
|||
* Source: <https://freesound.org/people/GoodListener/sounds/322454/>
|
||||
* `mobs_mc_horse_death.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/GoodListener/sounds/322445/>
|
||||
* [Garuda1982](https://freesound.org/people/Garuda1982/)
|
||||
* `mobs_mc_donkey_random.1.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_donkey_hurt.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_donkey_death.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/Garuda1982/sounds/539505/>
|
||||
* [JarredGibb](https://freesound.org/people/JarredGibb/sounds/233131/)
|
||||
* `mobs_mc_donkey_random.2.ogg` (CC0)
|
||||
* [ERH](https://freesound.org/people/ERH/)
|
||||
* `mobs_mc_horse_random.2.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/ERH/sounds/32043/>
|
||||
|
@ -228,10 +164,6 @@ Origin of those models:
|
|||
* [suonho](https://freesound.org/people/suonho/)
|
||||
* `mobs_mc_bat_idle.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/suonho/sounds/59344/>
|
||||
* [toefur](https://freesound.org/people/toefur/)
|
||||
* `mobs_mc_bat_hurt.*.ogg` (CC0)
|
||||
* `mobs_mc_bat_death.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/toefur/sounds/288941/>
|
||||
* [cmusounddesign](https://freesound.org/people/cmusounddesign/)
|
||||
* `mobs_mc_cat_hiss.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/cmusounddesign/sounds/71899/>
|
||||
|
@ -241,16 +173,6 @@ Origin of those models:
|
|||
* [ebcrosby](https://freesound.org/people/ebcrosby/)
|
||||
* `mobs_mc_ocelot_hurt.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/ebcrosby/sounds/332979/>
|
||||
* Hybrid Dog (forum.minetest.net)
|
||||
* `mobs_mc_wolf_hurt.*.ogg` (CC0)
|
||||
* `mobs_mc_wolf_bark.*.ogg` (CC0)
|
||||
* `mobs_mc_wolf_death.*.ogg` (CC0)
|
||||
* `mobs_mc_wolf_growl.*.ogg` (CC0)
|
||||
* Sounds modified and simplified
|
||||
* Source: "dogblocks" mod by Hybrid Dog <https://github.com/HybridDog/dogblocks/>
|
||||
* [cliftoncarlson](https://freesound.org/people/cliftonmcarlson/)
|
||||
* `mobs_mc_wolf_take_bone.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/cliftonmcarlson/sounds/392883/>
|
||||
* [Inocodum](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3115)
|
||||
* `mobs_mc_silverfish_hurt.ogg` (CC BY-SA 4.0)
|
||||
* `mobs_mc_silverfish_death.ogg` (CC BY-SA 4.0)
|
||||
|
@ -264,45 +186,6 @@ Origin of those models:
|
|||
* [kbnevel](https://freesound.org/people/kbnevel/)
|
||||
* `mobs_mc_magma_cube_attack.ogg` (CC0)
|
||||
* Derived from: <https://freesound.org/people/kbnevel/sounds/119863/>
|
||||
* [InspectorJ](https://freesound.org/people/InspectorJ/sounds/429591/)
|
||||
* `mobs_mc_animal_eat_generic.ogg` (CC BY 3.0)
|
||||
* Source: <https://freesound.org/people/InspectorJ/>
|
||||
* [tbsounddesigns](https://freesound.org/people/tbsounddesigns/)
|
||||
* `mobs_mc_bear_random.*.ogg` (CC BY 3.0)
|
||||
* Source 1: <https://freesound.org/people/tbsounddesigns/sounds/416853/>
|
||||
* Source 2: <https://freesound.org/people/tbsounddesigns/sounds/416857/>
|
||||
* Source 3: <https://freesound.org/people/tbsounddesigns/sounds/416855/>
|
||||
* `mobs_mc_bear_growl.*.ogg` (CC BY 3.0)
|
||||
* Source 1: <https://freesound.org/people/tbsounddesigns/sounds/416861/>
|
||||
* Source 2: <https://freesound.org/people/tbsounddesigns/sounds/416859/>
|
||||
* Source 3: <https://freesound.org/people/tbsounddesigns/sounds/416862/>
|
||||
* [YleArkisto](https://freesound.org/people/YleArkisto/)
|
||||
* `mobs_mc_bear_attack.*.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_bear_death.*.ogg` (CC BY 3.0)
|
||||
* `mobs_mc_bear_hurt.1.ogg` (CC BY 3.0)
|
||||
* Changes were made
|
||||
* Source: <https://freesound.org/people/YleArkisto/sounds/249441/>
|
||||
* [alexo400](https://freesound.org/people/alexo400/)
|
||||
* `mobs_mc_snowman_death.*.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/alexo400/sounds/543385/>
|
||||
* [cabled\_mess](https://freesound.org/people/cabled_mess/)
|
||||
* `mobs_mc_snowman_hurt.2.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/cabled_mess/sounds/384424/>
|
||||
* `mobs_mc_snowman_hurt.3.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/cabled_mess/sounds/384421/>
|
||||
* [kessir](https://freesound.org/people/kessir/sounds/)
|
||||
* `mobs_mc_rabbit_hurt.*.ogg` (CC0)
|
||||
* `mobs_mc_rabbit_death.2.ogg` (CC0)
|
||||
* `mobs_mc_rabbit_death.3.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/kessir/sounds/372075/>
|
||||
* `mobs_mc_rabbit_attack.*.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/kessir/sounds/372076/>
|
||||
* `mobs_mc_rabbit_death.1.ogg` (CC0)
|
||||
* Source: <https://freesound.org/people/kessir/sounds/385850/>
|
||||
* [Alshred](https://freesound.org/people/Alshred/sounds/403773/)
|
||||
* `mobs_mc_rabbit_random.*.ogg` (CC0)
|
||||
* Changes were made.
|
||||
* Source: <https://freesound.org/people/Alshred/>
|
||||
|
||||
Note: Many of these sounds have been more or less modified to fit the game.
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@ mobs:register_mob("mobs_mc:bat", {
|
|||
visual_size = {x=1, y=1},
|
||||
sounds = {
|
||||
random = "mobs_mc_bat_idle",
|
||||
damage = "mobs_mc_bat_hurt",
|
||||
death = "mobs_mc_bat_death",
|
||||
distance = 16,
|
||||
},
|
||||
walk_velocity = 4.5,
|
||||
|
@ -35,19 +33,18 @@ mobs:register_mob("mobs_mc:bat", {
|
|||
run_speed = 80,
|
||||
run_start = 0,
|
||||
run_end = 40,
|
||||
die_speed = 60,
|
||||
-- TODO: Less ugly death animation
|
||||
--[[ die_speed = 60,
|
||||
die_start = 40,
|
||||
die_end = 80,
|
||||
die_loop = false,
|
||||
]]
|
||||
},
|
||||
walk_chance = 100,
|
||||
|
||||
fall_damage = 0,
|
||||
view_range = 16,
|
||||
fear_height = 0,
|
||||
|
||||
jump = false,
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@ mobs:register_mob("mobs_mc:blaze", {
|
|||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
hp_max = 20,
|
||||
xp_min = 10,
|
||||
xp_max = 10,
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3},
|
||||
rotate = -180,
|
||||
visual = "mesh",
|
||||
|
@ -24,7 +22,7 @@ mobs:register_mob("mobs_mc:blaze", {
|
|||
textures = {
|
||||
{"mobs_mc_blaze.png"},
|
||||
},
|
||||
armor = { fleshy = 100, snowball_vulnerable = 100, water_vulnerable = 100 },
|
||||
armor = { fleshy = 100, snowball_vulnerable = 100 },
|
||||
visual_size = {x=3, y=3},
|
||||
sounds = {
|
||||
random = "mobs_mc_blaze_breath",
|
||||
|
@ -41,8 +39,7 @@ mobs:register_mob("mobs_mc:blaze", {
|
|||
{name = mobs_mc.items.blaze_rod,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
max = 1,},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 25,
|
||||
|
@ -71,10 +68,8 @@ mobs:register_mob("mobs_mc:blaze", {
|
|||
jump = true,
|
||||
jump_height = 4,
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
fear_height = 0,
|
||||
glow = 14,
|
||||
fire_resistant = true,
|
||||
})
|
||||
|
||||
mobs:spawn_specific("mobs_mc:blaze", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 5000, 3, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max)
|
||||
|
@ -88,10 +83,6 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
|||
|
||||
-- Direct hit, no fire... just plenty of pain
|
||||
hit_player = function(self, player)
|
||||
if rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[player:get_player_name()] = "fireball"
|
||||
end
|
||||
mcl_burning.set_on_fire(player, 5, "blaze")
|
||||
player:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 5},
|
||||
|
@ -99,7 +90,6 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
|||
end,
|
||||
|
||||
hit_mob = function(self, mob)
|
||||
mcl_burning.set_on_fire(mob, 5)
|
||||
mob:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 5},
|
||||
|
|
|
@ -14,8 +14,6 @@ mobs:register_mob("mobs_mc:chicken", {
|
|||
|
||||
hp_min = 4,
|
||||
hp_max = 4,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2},
|
||||
runaway = true,
|
||||
floats = 1,
|
||||
|
@ -32,28 +30,23 @@ mobs:register_mob("mobs_mc:chicken", {
|
|||
{name = mobs_mc.items.chicken_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.feather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
},
|
||||
fall_damage = 0,
|
||||
fall_speed = -2.25,
|
||||
sounds = {
|
||||
random = "mobs_mc_chicken_buck",
|
||||
damage = "mobs_mc_chicken_hurt",
|
||||
death = "mobs_mc_chicken_hurt",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
random = "mobs_chicken",
|
||||
-- TODO: death, damage
|
||||
distance = 16,
|
||||
},
|
||||
sounds_child = {
|
||||
random = "mobs_mc_chicken_child",
|
||||
damage = "mobs_mc_chicken_child",
|
||||
death = "mobs_mc_chicken_child",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
|
|
|
@ -7,8 +7,6 @@ local cow_def = {
|
|||
spawn_class = "passive",
|
||||
hp_min = 10,
|
||||
hp_max = 10,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_cow.b3d",
|
||||
|
@ -23,28 +21,24 @@ local cow_def = {
|
|||
{name = mobs_mc.items.beef_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 3,
|
||||
looting = "common",},
|
||||
max = 3,},
|
||||
{name = mobs_mc.items.leather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
},
|
||||
runaway = true,
|
||||
sounds = {
|
||||
random = "mobs_mc_cow",
|
||||
damage = "mobs_mc_cow_hurt",
|
||||
death = "mobs_mc_cow_hurt",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 25, walk_speed = 40,
|
||||
run_speed = 60, stand_start = 0,
|
||||
stand_end = 0, walk_start = 0,
|
||||
walk_end = 40, run_start = 0,
|
||||
run_end = 40,
|
||||
stand_speed = 25, walk_speed = 25, run_speed = 50,
|
||||
stand_start = 0, stand_end = 0,
|
||||
walk_start = 0, walk_end = 40,
|
||||
run_start = 0, run_end = 40,
|
||||
},
|
||||
follow = mobs_mc.follow.cow,
|
||||
on_rightclick = function(self, clicker)
|
||||
|
@ -59,7 +53,6 @@ local cow_def = {
|
|||
if item:get_name() == mobs_mc.items.bucket and clicker:get_inventory() then
|
||||
local inv = clicker:get_inventory()
|
||||
inv:remove_item("main", mobs_mc.items.bucket)
|
||||
minetest.sound_play("mobs_mc_cow_milk", {pos=self.object:get_pos(), gain=0.6})
|
||||
-- if room add bucket of milk to inventory, otherwise drop as item
|
||||
if inv:room_for_item("main", {name=mobs_mc.items.milk}) then
|
||||
clicker:get_inventory():add_item("main", mobs_mc.items.milk)
|
||||
|
@ -95,7 +88,7 @@ mooshroom_def.on_rightclick = function(self, clicker)
|
|||
-- Use shears to get mushrooms and turn mooshroom into cow
|
||||
if item:get_name() == mobs_mc.items.shears then
|
||||
local pos = self.object:get_pos()
|
||||
minetest.sound_play("mcl_tools_shears_cut", {pos = pos}, true)
|
||||
minetest.sound_play("shears", {pos = pos}, true)
|
||||
|
||||
if self.base_texture[1] == "mobs_mc_mooshroom_brown.png" then
|
||||
minetest.add_item({x=pos.x, y=pos.y+1.4, z=pos.z}, mobs_mc.items.mushroom_brown .. " 5")
|
||||
|
@ -116,7 +109,6 @@ mooshroom_def.on_rightclick = function(self, clicker)
|
|||
elseif item:get_name() == mobs_mc.items.bucket and clicker:get_inventory() then
|
||||
local inv = clicker:get_inventory()
|
||||
inv:remove_item("main", mobs_mc.items.bucket)
|
||||
minetest.sound_play("mobs_mc_cow_milk", {pos=self.object:get_pos(), gain=0.6})
|
||||
-- If room, add milk to inventory, otherwise drop as item
|
||||
if inv:room_for_item("main", {name=mobs_mc.items.milk}) then
|
||||
clicker:get_inventory():add_item("main", mobs_mc.items.milk)
|
||||
|
@ -129,7 +121,6 @@ mooshroom_def.on_rightclick = function(self, clicker)
|
|||
elseif item:get_name() == mobs_mc.items.bowl and clicker:get_inventory() then
|
||||
local inv = clicker:get_inventory()
|
||||
inv:remove_item("main", mobs_mc.items.bowl)
|
||||
minetest.sound_play("mobs_mc_cow_mushroom_stew", {pos=self.object:get_pos(), gain=0.6})
|
||||
-- If room, add mushroom stew to inventory, otherwise drop as item
|
||||
if inv:room_for_item("main", {name=mobs_mc.items.mushroom_stew}) then
|
||||
clicker:get_inventory():add_item("main", mobs_mc.items.mushroom_stew)
|
||||
|
|
|
@ -14,15 +14,12 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
hp_max = 20,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.69, 0.3},
|
||||
pathfinding = 1,
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_creeper.b3d",
|
||||
textures = {
|
||||
{"mobs_mc_creeper.png",
|
||||
"mobs_mc_empty.png"},
|
||||
{"mobs_mc_creeper.png"},
|
||||
},
|
||||
visual_size = {x=3, y=3},
|
||||
sounds = {
|
||||
|
@ -40,10 +37,7 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
attack_type = "explode",
|
||||
|
||||
explosion_strength = 3,
|
||||
explosion_radius = 3.5,
|
||||
explosion_damage_radius = 3.5,
|
||||
explosiontimer_reset_radius = 6,
|
||||
reach = 3,
|
||||
reach = 4,
|
||||
explosion_timer = 1.5,
|
||||
allow_fuse_reset = true,
|
||||
stop_to_explode = true,
|
||||
|
@ -75,21 +69,17 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||
if self._forced_explosion_countdown_timer <= 0 then
|
||||
mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
|
||||
mobs:boom(self, self.object:get_pos(), self.explosion_strength)
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_die = function(self, pos, cmi_cause)
|
||||
-- Drop a random music disc when killed by skeleton or stray
|
||||
if cmi_cause and cmi_cause.type == "punch" then
|
||||
local luaentity = cmi_cause.puncher and cmi_cause.puncher:get_luaentity()
|
||||
if luaentity and luaentity.name:find("arrow") then
|
||||
local shooter_luaentity = luaentity._shooter and luaentity._shooter:get_luaentity()
|
||||
if shooter_luaentity and (shooter_luaentity.name == "mobs_mc:skeleton" or shooter_luaentity.name == "mobs_mc:stray") then
|
||||
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, mobs_mc.items.music_discs[math.random(1, #mobs_mc.items.music_discs)])
|
||||
end
|
||||
end
|
||||
on_die = function(self, pos)
|
||||
-- Drop a random music disc
|
||||
-- TODO: Only do this if killed by skeleton
|
||||
if math.random(1, 200) == 1 then
|
||||
local r = math.random(1, #mobs_mc.items.music_discs)
|
||||
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, mobs_mc.items.music_discs[r])
|
||||
end
|
||||
end,
|
||||
maxdrops = 2,
|
||||
|
@ -97,8 +87,7 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
{name = mobs_mc.items.gunpowder,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
|
||||
-- Head
|
||||
-- TODO: Only drop if killed by charged creeper
|
||||
|
@ -128,127 +117,6 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
view_range = 16,
|
||||
})
|
||||
|
||||
mobs:register_mob("mobs_mc:creeper_charged", {
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
hp_max = 20,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.69, 0.3},
|
||||
pathfinding = 1,
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_creeper.b3d",
|
||||
textures = {
|
||||
{"mobs_mc_creeper.png",
|
||||
"mobs_mc_creeper_charge.png"},
|
||||
},
|
||||
visual_size = {x=3, y=3},
|
||||
sounds = {
|
||||
attack = "tnt_ignite",
|
||||
death = "mobs_mc_creeper_death",
|
||||
damage = "mobs_mc_creeper_hurt",
|
||||
fuse = "tnt_ignite",
|
||||
explode = "tnt_explode",
|
||||
distance = 16,
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
walk_velocity = 1.05,
|
||||
run_velocity = 2.1,
|
||||
runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" },
|
||||
attack_type = "explode",
|
||||
|
||||
explosion_strength = 6,
|
||||
explosion_radius = 8,
|
||||
explosion_damage_radius = 8,
|
||||
explosiontimer_reset_radius = 6,
|
||||
reach = 3,
|
||||
explosion_timer = 1.5,
|
||||
allow_fuse_reset = true,
|
||||
stop_to_explode = true,
|
||||
|
||||
-- Force-ignite creeper with flint and steel and explode after 1.5 seconds.
|
||||
-- TODO: Make creeper flash after doing this as well.
|
||||
-- TODO: Test and debug this code.
|
||||
on_rightclick = function(self, clicker)
|
||||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
return
|
||||
end
|
||||
local item = clicker:get_wielded_item()
|
||||
if item:get_name() == mobs_mc.items.flint_and_steel then
|
||||
if not minetest.is_creative_enabled(clicker:get_player_name()) then
|
||||
-- Wear tool
|
||||
local wdef = item:get_definition()
|
||||
item:add_wear(1000)
|
||||
-- Tool break sound
|
||||
if item:get_count() == 0 and wdef.sound and wdef.sound.breaks then
|
||||
minetest.sound_play(wdef.sound.breaks, {pos = clicker:get_pos(), gain = 0.5}, true)
|
||||
end
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
self._forced_explosion_countdown_timer = self.explosion_timer
|
||||
minetest.sound_play(self.sounds.attack, {pos = self.object:get_pos(), gain = 1, max_hear_distance = 16}, true)
|
||||
end
|
||||
end,
|
||||
do_custom = function(self, dtime)
|
||||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||
if self._forced_explosion_countdown_timer <= 0 then
|
||||
mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_die = function(self, pos, cmi_cause)
|
||||
-- Drop a random music disc when killed by skeleton or stray
|
||||
if cmi_cause and cmi_cause.type == "punch" then
|
||||
local luaentity = cmi_cause.puncher and cmi_cause.puncher:get_luaentity()
|
||||
if luaentity and luaentity.name:find("arrow") then
|
||||
local shooter_luaentity = luaentity._shooter and luaentity._shooter:get_luaentity()
|
||||
if shooter_luaentity and (shooter_luaentity.name == "mobs_mc:skeleton" or shooter_luaentity.name == "mobs_mc:stray") then
|
||||
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, mobs_mc.items.music_discs[math.random(1, #mobs_mc.items.music_discs)])
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
maxdrops = 2,
|
||||
drops = {
|
||||
{name = mobs_mc.items.gunpowder,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
-- Head
|
||||
-- TODO: Only drop if killed by charged creeper
|
||||
{name = mobs_mc.items.head_creeper,
|
||||
chance = 200, -- 0.5%
|
||||
min = 1,
|
||||
max = 1,},
|
||||
},
|
||||
animation = {
|
||||
speed_normal = 24,
|
||||
speed_run = 48,
|
||||
stand_start = 0,
|
||||
stand_end = 23,
|
||||
walk_start = 24,
|
||||
walk_end = 49,
|
||||
run_start = 24,
|
||||
run_end = 49,
|
||||
hurt_start = 110,
|
||||
hurt_end = 139,
|
||||
death_start = 140,
|
||||
death_end = 189,
|
||||
look_start = 50,
|
||||
look_end = 108,
|
||||
},
|
||||
floats = 1,
|
||||
fear_height = 4,
|
||||
view_range = 16,
|
||||
--Having trouble when fire is placed with lightning
|
||||
fire_resistant = true,
|
||||
glow = 3,
|
||||
})
|
||||
|
||||
mobs:spawn_specific("mobs_mc:creeper", mobs_mc.spawn.solid, {"air"}, 0, 7, 20, 16500, 2, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max)
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
mcl_init
|
||||
mcl_particles
|
||||
default?
|
||||
mcl_mobs
|
||||
mcl_tnt?
|
||||
|
|
|
@ -12,8 +12,6 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
|||
walk_chance = 100,
|
||||
hp_max = 200,
|
||||
hp_min = 200,
|
||||
xp_min = 500,
|
||||
xp_max = 500,
|
||||
collisionbox = {-2, 3, -2, 2, 5, 2},
|
||||
physical = false,
|
||||
visual = "mesh",
|
||||
|
@ -25,7 +23,6 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
|||
view_range = 35,
|
||||
walk_velocity = 6,
|
||||
run_velocity = 6,
|
||||
can_despawn = false,
|
||||
sounds = {
|
||||
-- TODO: more sounds
|
||||
shoot_attack = "mobs_mc_ender_dragon_shoot",
|
||||
|
@ -37,12 +34,17 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
|||
jump = true,
|
||||
jump_height = 14,
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
dogshoot_switch = 1,
|
||||
dogshoot_count_max =5,
|
||||
dogshoot_count2_max = 5,
|
||||
passive = false,
|
||||
attack_animals = true,
|
||||
drops = {
|
||||
{name = mobs_mc.items.dragon_egg,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 1},
|
||||
},
|
||||
lava_damage = 0,
|
||||
fire_damage = 0,
|
||||
on_rightclick = nil,
|
||||
|
@ -50,26 +52,14 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
|||
arrow = "mobs_mc:dragon_fireball",
|
||||
shoot_interval = 0.5,
|
||||
shoot_offset = -1.0,
|
||||
xp_min = 12000,
|
||||
xp_max = 12000,
|
||||
animation = {
|
||||
fly_speed = 8, stand_speed = 8,
|
||||
stand_start = 0, stand_end = 20,
|
||||
walk_start = 0, walk_end = 20,
|
||||
run_start = 0, run_end = 20,
|
||||
},
|
||||
|
||||
ignores_nametag = true,
|
||||
on_die = function(self, own_pos)
|
||||
if self._egg_spawn_pos then
|
||||
local pos = minetest.string_to_pos(self._egg_spawn_pos)
|
||||
--if minetest.get_node(pos).buildable_to then
|
||||
minetest.set_node(pos, {name = mobs_mc.items.dragon_egg})
|
||||
return
|
||||
--end
|
||||
end
|
||||
minetest.add_item(own_pos, mobs_mc.items.dragon_egg)
|
||||
end,
|
||||
fire_resistant = true,
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
-- However, they have a reduced viewing range to make them less dangerous.
|
||||
-- This differs from MC, in which endermen only become hostile when provoked,
|
||||
-- and they are provoked by looking directly at them.
|
||||
-- TODO: Implement MC behaviour.
|
||||
|
||||
-- Rootyjr
|
||||
-----------------------------
|
||||
|
@ -26,16 +27,6 @@
|
|||
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
local telesound = function(pos, is_source)
|
||||
local snd
|
||||
if is_source then
|
||||
snd = "mobs_mc_enderman_teleport_src"
|
||||
else
|
||||
snd = "mobs_mc_enderman_teleport_dst"
|
||||
end
|
||||
minetest.sound_play(snd, {pos=pos, max_hear_distance=16}, true)
|
||||
end
|
||||
|
||||
--###################
|
||||
--################### ENDERMAN
|
||||
--###################
|
||||
|
@ -43,10 +34,10 @@ end
|
|||
local pr = PseudoRandom(os.time()*(-334))
|
||||
|
||||
-- How freqeuntly to take and place blocks, in seconds
|
||||
local take_frequency_min = 235
|
||||
local take_frequency_max = 245
|
||||
local place_frequency_min = 235
|
||||
local place_frequency_max = 245
|
||||
local take_frequency_min = 25
|
||||
local take_frequency_max = 90
|
||||
local place_frequency_min = 10
|
||||
local place_frequency_max = 30
|
||||
|
||||
-- Create the textures table for the enderman, depending on which kind of block
|
||||
-- the enderman holds (if any).
|
||||
|
@ -190,14 +181,13 @@ end
|
|||
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
|
||||
|
||||
mobs:register_mob("mobs_mc:enderman", {
|
||||
-- TODO: Endermen should be classified as passive
|
||||
type = "monster",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
pathfinding = 1,
|
||||
hp_min = 40,
|
||||
hp_max = 40,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 2.89, 0.3},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_enderman.b3d",
|
||||
|
@ -205,11 +195,9 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
sounds = {
|
||||
-- TODO: Custom war cry sound
|
||||
war_cry = "mobs_sandmonster",
|
||||
death = {name="mobs_mc_enderman_death", gain=0.7},
|
||||
damage = {name="mobs_mc_enderman_hurt", gain=0.5},
|
||||
random = {name="mobs_mc_enderman_random", gain=0.5},
|
||||
death = "green_slime_death",
|
||||
-- TODO: damage, random
|
||||
distance = 16,
|
||||
},
|
||||
walk_velocity = 0.2,
|
||||
|
@ -220,11 +208,11 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
{name = mobs_mc.items.ender_pearl,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,
|
||||
looting = "common"},
|
||||
max = 1,},
|
||||
},
|
||||
animation = select_enderman_animation("normal"),
|
||||
_taken_node = "",
|
||||
-- TODO: Teleport enderman on damage, etc.
|
||||
do_custom = function(self, dtime)
|
||||
-- PARTICLE BEHAVIOUR HERE.
|
||||
local enderpos = self.object:get_pos()
|
||||
|
@ -242,55 +230,52 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
})
|
||||
end
|
||||
-- RAIN DAMAGE / EVASIVE WARP BEHAVIOUR HERE.
|
||||
local dim = mcl_worlds.pos_to_dimension(enderpos)
|
||||
if dim == "overworld" then
|
||||
if mcl_weather.state == "rain" or mcl_weather.state == "lightning" then
|
||||
local damage = true
|
||||
local enderpos = self.object:get_pos()
|
||||
enderpos.y = enderpos.y+2.89
|
||||
local height = {x=enderpos.x, y=enderpos.y+512,z=enderpos.z}
|
||||
local ray = minetest.raycast(enderpos, height, true)
|
||||
-- Check for blocks above enderman.
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.type == "node" then
|
||||
local nn = minetest.get_node(minetest.get_pointed_thing_position(pointed_thing)).name
|
||||
local def = minetest.registered_nodes[nn]
|
||||
if (not def) or def.walkable then
|
||||
-- There's a node in the way. Delete arrow without damage
|
||||
damage = false
|
||||
break
|
||||
end
|
||||
if mcl_weather.state == "rain" or mcl_weather.state == "lightning" then
|
||||
local damage = true
|
||||
local enderpos = self.object:get_pos()
|
||||
enderpos.y = enderpos.y+2.89
|
||||
local height = {x=enderpos.x, y=enderpos.y+512,z=enderpos.z}
|
||||
local ray = minetest.raycast(enderpos, height, true)
|
||||
-- Check for blocks above enderman.
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.type == "node" then
|
||||
local nn = minetest.get_node(minetest.get_pointed_thing_position(pointed_thing)).name
|
||||
local def = minetest.registered_nodes[nn]
|
||||
if (not def) or def.walkable then
|
||||
-- There's a node in the way. Delete arrow without damage
|
||||
damage = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if damage == true then
|
||||
self.state = ""
|
||||
--rain hurts enderman
|
||||
self.object:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=self._damage},
|
||||
}, nil)
|
||||
--randomly teleport hopefully under something.
|
||||
self:teleport(nil)
|
||||
end
|
||||
end
|
||||
else return end
|
||||
|
||||
if damage == true then
|
||||
self.state = ""
|
||||
--rain hurts enderman
|
||||
self.object:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=self._damage},
|
||||
}, nil)
|
||||
--randomly teleport hopefully under something.
|
||||
self:teleport(nil)
|
||||
end
|
||||
end
|
||||
-- AGRESSIVELY WARP/CHASE PLAYER BEHAVIOUR HERE.
|
||||
if self.state == "attack" then
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
--self:teleport(nil)
|
||||
--self.state = ""
|
||||
--else
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
self.state = ""
|
||||
else
|
||||
if self.attack then
|
||||
local target = self.attack
|
||||
local pos = target:get_pos()
|
||||
target = self.attack
|
||||
pos = target:get_pos()
|
||||
if pos ~= nil then
|
||||
if vector.distance(self.object:get_pos(), target:get_pos()) > 10 then
|
||||
self:teleport(target)
|
||||
end
|
||||
end
|
||||
end
|
||||
--end
|
||||
end
|
||||
end
|
||||
-- ARROW / DAYTIME PEOPLE AVOIDANCE BEHAVIOUR HERE.
|
||||
-- Check for arrows and people nearby.
|
||||
|
@ -301,9 +286,9 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
if obj then
|
||||
if minetest.is_player(obj) then
|
||||
-- Warp from players during day.
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
-- self:teleport(nil)
|
||||
--end
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
end
|
||||
else
|
||||
local lua = obj:get_luaentity()
|
||||
if lua then
|
||||
|
@ -318,18 +303,17 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
local enderpos = self.object:get_pos()
|
||||
if self.provoked == "broke_contact" then
|
||||
self.provoked = "false"
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
-- self:teleport(nil)
|
||||
-- self.state = ""
|
||||
--else
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
self.state = ""
|
||||
else
|
||||
if self.attack ~= nil then
|
||||
self.state = 'attack'
|
||||
end
|
||||
--end
|
||||
end
|
||||
end
|
||||
-- Check to see if people are near by enough to look at us.
|
||||
local objs = minetest.get_objects_inside_radius(enderpos, 64)
|
||||
local obj
|
||||
for n = 1, #objs do
|
||||
obj = objs[n]
|
||||
if obj then
|
||||
|
@ -377,7 +361,7 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
self._take_place_timer = 0
|
||||
self._next_take_place_time = math.random(place_frequency_min, place_frequency_max)
|
||||
local pos = self.object:get_pos()
|
||||
local takable_nodes = minetest.find_nodes_in_area_under_air({x=pos.x-2, y=pos.y-1, z=pos.z-2}, {x=pos.x+2, y=pos.y+1, z=pos.z+2}, mobs_mc.enderman_takable)
|
||||
local takable_nodes = minetest.find_nodes_in_area({x=pos.x-2, y=pos.y-1, z=pos.z-2}, {x=pos.x+2, y=pos.y+1, z=pos.z+2}, mobs_mc.enderman_takable)
|
||||
if #takable_nodes >= 1 then
|
||||
local r = pr:next(1, #takable_nodes)
|
||||
local take_pos = takable_nodes[r]
|
||||
|
@ -477,9 +461,7 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
end
|
||||
end
|
||||
if telepos then
|
||||
telesound(self.object:get_pos(), false)
|
||||
self.object:set_pos(telepos)
|
||||
telesound(telepos, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -507,10 +489,7 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
end
|
||||
end
|
||||
if node_ok then
|
||||
telesound(self.object:get_pos(), false)
|
||||
local telepos = {x=nodepos.x, y=nodepos.y+1, z=nodepos.z}
|
||||
self.object:set_pos(telepos)
|
||||
telesound(telepos, true)
|
||||
self.object:set_pos({x=nodepos.x, y=nodepos.y+1, z=nodepos.z})
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -531,16 +510,15 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
do_punch = function(self, hitter, tflp, tool_caps, dir)
|
||||
-- damage from rain caused by itself so we don't want it to attack itself.
|
||||
if hitter ~= self.object and hitter ~= nil then
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
-- self:teleport(nil)
|
||||
--else
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
else
|
||||
self:teleport(hitter)
|
||||
self.attack=hitter
|
||||
self.state="attack"
|
||||
--end
|
||||
end
|
||||
end
|
||||
end,
|
||||
armor = { fleshy = 100, water_vulnerable = 100 },
|
||||
water_damage = 8,
|
||||
view_range = 64,
|
||||
fear_height = 4,
|
||||
|
|
|
@ -10,9 +10,7 @@ mobs:register_mob("mobs_mc:endermite", {
|
|||
passive = false,
|
||||
hp_min = 8,
|
||||
hp_max = 8,
|
||||
xp_min = 3,
|
||||
xp_max = 3,
|
||||
armor = {fleshy = 100, arthropod = 100},
|
||||
armor = 100,
|
||||
group_attack = true,
|
||||
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.29, 0.2},
|
||||
visual = "mesh",
|
||||
|
@ -23,10 +21,9 @@ mobs:register_mob("mobs_mc:endermite", {
|
|||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = false,
|
||||
sounds = {
|
||||
random = "mobs_mc_endermite_random",
|
||||
damage = "mobs_mc_endermite_hurt",
|
||||
death = "mobs_mc_endermite_death",
|
||||
random = "mobs_rat",
|
||||
distance = 16,
|
||||
-- TODO: more sounds
|
||||
},
|
||||
walk_velocity = 1,
|
||||
run_velocity = 2,
|
||||
|
|
|
@ -17,8 +17,6 @@ mobs:register_mob("mobs_mc:ghast", {
|
|||
group_attack = true,
|
||||
hp_min = 10,
|
||||
hp_max = 10,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
collisionbox = {-2, 5, -2, 2, 9, 2},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_ghast.b3d",
|
||||
|
@ -38,8 +36,8 @@ mobs:register_mob("mobs_mc:ghast", {
|
|||
walk_velocity = 1.6,
|
||||
run_velocity = 3.2,
|
||||
drops = {
|
||||
{name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2, looting = "common"},
|
||||
{name = mobs_mc.items.ghast_tear, chance = 10/6, min = 0, max = 1, looting = "common", looting_ignore_chance = true},
|
||||
{name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.ghast_tear, chance = 3,min = 0,max = 1,},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 50, walk_speed = 50, run_speed = 50,
|
||||
|
@ -60,9 +58,6 @@ mobs:register_mob("mobs_mc:ghast", {
|
|||
jump_height = 4,
|
||||
floats=1,
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
instant_death = true,
|
||||
fire_resistant = true,
|
||||
})
|
||||
|
||||
|
||||
|
@ -76,9 +71,6 @@ mobs:register_arrow("mobs_mc:fireball", {
|
|||
velocity = 15,
|
||||
|
||||
hit_player = function(self, player)
|
||||
if rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[player:get_player_name()] = "fireball"
|
||||
end
|
||||
player:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 6},
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
-- v1.4
|
||||
|
||||
--###################
|
||||
--################### GUARDIAN
|
||||
--###################
|
||||
|
@ -9,8 +11,6 @@ mobs:register_mob("mobs_mc:guardian", {
|
|||
spawn_class = "hostile",
|
||||
hp_min = 30,
|
||||
hp_max = 30,
|
||||
xp_min = 10,
|
||||
xp_max = 10,
|
||||
breath_max = -1,
|
||||
passive = false,
|
||||
attack_type = "dogfight",
|
||||
|
@ -28,11 +28,8 @@ mobs:register_mob("mobs_mc:guardian", {
|
|||
},
|
||||
visual_size = {x=3, y=3},
|
||||
sounds = {
|
||||
random = "mobs_mc_guardian_random",
|
||||
war_cry = "mobs_mc_guardian_random",
|
||||
damage = {name="mobs_mc_guardian_hurt", gain=0.3},
|
||||
death = "mobs_mc_guardian_death",
|
||||
flop = "mobs_mc_squid_flop",
|
||||
damage = "mobs_mc_squid_hurt",
|
||||
-- TODO: more and better sounds
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
|
@ -46,8 +43,7 @@ mobs:register_mob("mobs_mc:guardian", {
|
|||
{name = mobs_mc.items.prismarine_shard,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 32,
|
||||
looting = "common",},
|
||||
max = 32,},
|
||||
-- TODO: Reduce of drops when ocean monument is ready.
|
||||
|
||||
-- The following drops are approximations
|
||||
|
@ -55,42 +51,31 @@ mobs:register_mob("mobs_mc:guardian", {
|
|||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 4,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.prismarine_crystals,
|
||||
chance = 4,
|
||||
min = 1,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
|
||||
-- Rare drop: fish
|
||||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 160, -- 2.5% / 4
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.salmon_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.clownfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.pufferfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
max = 1,},
|
||||
},
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
fly_in = { mobs_mc.items.water_source, mobs_mc.items.river_water_source },
|
||||
jump = false,
|
||||
view_range = 16,
|
||||
|
|
|
@ -11,8 +11,6 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
|||
spawn_class = "hostile",
|
||||
hp_min = 80,
|
||||
hp_max = 80,
|
||||
xp_min = 10,
|
||||
xp_max = 10,
|
||||
breath_max = -1,
|
||||
passive = false,
|
||||
attack_type = "dogfight",
|
||||
|
@ -30,12 +28,8 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
|||
},
|
||||
visual_size = {x=7, y=7},
|
||||
sounds = {
|
||||
random = "mobs_mc_guardian_random",
|
||||
war_cry = "mobs_mc_guardian_random",
|
||||
damage = {name="mobs_mc_guardian_hurt", gain=0.3},
|
||||
death = "mobs_mc_guardian_death",
|
||||
flop = "mobs_mc_squid_flop",
|
||||
base_pitch = 0.6,
|
||||
damage = "mobs_mc_squid_hurt",
|
||||
-- TODO: more and better sounds
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
|
@ -51,8 +45,7 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
|||
{name = mobs_mc.items.prismarine_shard,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 64,
|
||||
looting = "common",},
|
||||
max = 64,},
|
||||
|
||||
-- TODO: Only drop if killed by player
|
||||
{name = mobs_mc.items.wet_sponge,
|
||||
|
@ -65,42 +58,31 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
|||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 4,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.prismarine_crystals,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 10,
|
||||
looting = "common",},
|
||||
max = 10,},
|
||||
|
||||
-- Rare drop: fish
|
||||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 160, -- 2.5% / 4
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.salmon_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.clownfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.pufferfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
max = 1,},
|
||||
},
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
fly_in = { mobs_mc.items.water_source, mobs_mc.items.river_water_source },
|
||||
jump = false,
|
||||
view_range = 16,
|
||||
|
|
|
@ -96,7 +96,7 @@ local horse = {
|
|||
walk_speed = 25,
|
||||
walk_start = 0,
|
||||
walk_end = 40,
|
||||
run_speed = 60,
|
||||
run_speed = 50,
|
||||
run_start = 0,
|
||||
run_end = 40,
|
||||
},
|
||||
|
@ -106,7 +106,6 @@ local horse = {
|
|||
-- TODO: Separate damage sound
|
||||
damage = "mobs_mc_horse_death",
|
||||
death = "mobs_mc_horse_death",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
fear_height = 4,
|
||||
|
@ -117,8 +116,6 @@ local horse = {
|
|||
passive = true,
|
||||
hp_min = 15,
|
||||
hp_max = 30,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
floats = 1,
|
||||
makes_footstep_sound = true,
|
||||
jump = true,
|
||||
|
@ -127,8 +124,7 @@ local horse = {
|
|||
{name = mobs_mc.items.leather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
},
|
||||
|
||||
do_custom = function(self, dtime)
|
||||
|
@ -354,7 +350,6 @@ mobs:register_mob("mobs_mc:horse", horse)
|
|||
-- Skeleton horse
|
||||
local skeleton_horse = table.copy(horse)
|
||||
skeleton_horse.breath_max = -1
|
||||
skeleton_horse.armor = {undead = 100, fleshy = 100}
|
||||
skeleton_horse.textures = {{"blank.png", "mobs_mc_horse_skeleton.png", "blank.png"}}
|
||||
skeleton_horse.drops = {
|
||||
{name = mobs_mc.items.bone,
|
||||
|
@ -366,8 +361,6 @@ skeleton_horse.sounds = {
|
|||
random = "mobs_mc_skeleton_random",
|
||||
death = "mobs_mc_skeleton_death",
|
||||
damage = "mobs_mc_skeleton_hurt",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
base_pitch = 0.95,
|
||||
distance = 16,
|
||||
}
|
||||
skeleton_horse.harmed_by_heal = true
|
||||
|
@ -376,7 +369,6 @@ mobs:register_mob("mobs_mc:skeleton_horse", skeleton_horse)
|
|||
-- Zombie horse
|
||||
local zombie_horse = table.copy(horse)
|
||||
zombie_horse.breath_max = -1
|
||||
zombie_horse.armor = {undead = 100, fleshy = 100}
|
||||
zombie_horse.textures = {{"blank.png", "mobs_mc_horse_zombie.png", "blank.png"}}
|
||||
zombie_horse.drops = {
|
||||
{name = mobs_mc.items.rotten_flesh,
|
||||
|
@ -385,12 +377,9 @@ zombie_horse.drops = {
|
|||
max = 2,},
|
||||
}
|
||||
zombie_horse.sounds = {
|
||||
random = "mobs_mc_horse_random",
|
||||
-- TODO: Separate damage sound
|
||||
damage = "mobs_mc_horse_death",
|
||||
death = "mobs_mc_horse_death",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
base_pitch = 0.5,
|
||||
random = "mobs_mc_zombie_growl",
|
||||
death = "mobs_mc_zombie_death",
|
||||
damage = "mobs_mc_zombie_hurt",
|
||||
distance = 16,
|
||||
}
|
||||
zombie_horse.harmed_by_heal = true
|
||||
|
@ -405,13 +394,8 @@ donkey.animation = {
|
|||
stand_start = 0, stand_end = 0,
|
||||
walk_start = 0, walk_end = 40,
|
||||
}
|
||||
donkey.sounds = {
|
||||
random = "mobs_mc_donkey_random",
|
||||
damage = "mobs_mc_donkey_hurt",
|
||||
death = "mobs_mc_donkey_death",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
}
|
||||
-- TODO: donkey sounds
|
||||
donkey.sounds = nil
|
||||
donkey.visual_size = { x=horse.visual_size.x*d, y=horse.visual_size.y*d }
|
||||
donkey.collisionbox = {
|
||||
horse.collisionbox[1] * d,
|
||||
|
@ -431,8 +415,7 @@ local m = 0.94
|
|||
local mule = table.copy(donkey)
|
||||
mule.textures = {{"blank.png", "mobs_mc_mule.png", "blank.png"}}
|
||||
mule.visual_size = { x=horse.visual_size.x*m, y=horse.visual_size.y*m }
|
||||
mule.sounds = table.copy(donkey.sounds)
|
||||
mule.sounds.base_pitch = 1.15
|
||||
mule.sounds = horse.sounds
|
||||
mule.collisionbox = {
|
||||
horse.collisionbox[1] * m,
|
||||
horse.collisionbox[2] * m,
|
||||
|
|
|
@ -29,8 +29,6 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
spawn_class = "passive",
|
||||
hp_min = 15,
|
||||
hp_max = 30,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
passive = false,
|
||||
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.86, 0.45},
|
||||
visual = "mesh",
|
||||
|
@ -48,27 +46,21 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
runaway = true,
|
||||
walk_velocity = 1,
|
||||
run_velocity = 4.4,
|
||||
follow_velocity = 4.4,
|
||||
floats = 1,
|
||||
drops = {
|
||||
{name = mobs_mc.items.leather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
},
|
||||
fear_height = 4,
|
||||
sounds = {
|
||||
random = "mobs_mc_llama",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
-- TODO: Death and damage sounds
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
speed_normal = 24,
|
||||
run_speed = 60,
|
||||
run_start = 0,
|
||||
run_end = 40,
|
||||
stand_start = 0,
|
||||
stand_end = 0,
|
||||
walk_start = 0,
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
# textdomain: mobs_mc
|
||||
Totem of Undying=Тотем бессмертия
|
||||
A totem of undying is a rare artifact which may safe you from certain death.=Тотем бессмертия это редкий артефакт, способный спасти вас от смерти.
|
||||
The totem only works while you hold it in your hand. If you receive fatal damage, you are saved from death and you get a second chance with 1 HP. The totem is destroyed in the process, however.=Тотем работает только когда вы держите его в руке. Если вы получаете смертельный урон, вы спасаетесь от смерти и получаете второй шанс с 1 HP. Однако тотем при этом уничтожается.
|
||||
Agent=Агент
|
||||
Bat=Летучая мышь
|
||||
Blaze=Ифрит
|
||||
Chicken=Курица
|
||||
Cow=Корова
|
||||
Mooshroom=Гриб
|
||||
Creeper=Крипер
|
||||
Ender Dragon=Дракон Предела
|
||||
Enderman=Эндермен
|
||||
Endermite=Эндермит
|
||||
Ghast=Гаст
|
||||
Elder Guardian=Древний страж
|
||||
Guardian=Страж
|
||||
Horse=Лошадь
|
||||
Skeleton Horse=Скелет лошади
|
||||
Zombie Horse=Зомби-лошадь
|
||||
Donkey=Ослик
|
||||
Mule=Мул
|
||||
Iron Golem=Железный голем
|
||||
Llama=Лама
|
||||
Ocelot=Оцелот
|
||||
Parrot=Попугай
|
||||
Pig=Свинья
|
||||
Polar Bear=Полярный медведь
|
||||
Rabbit=Кролик
|
||||
Killer Bunny=Кролик-убийца
|
||||
Sheep=Овца
|
||||
Shulker=Шалкер
|
||||
Silverfish=Чешуйница
|
||||
Skeleton=Скелет
|
||||
Stray=Странник
|
||||
Wither Skeleton=Скелет-иссушитель
|
||||
Magma Cube=Лавовый куб
|
||||
Slime=Слизняк
|
||||
Snow Golem=Снежный голем
|
||||
Spider=Паук
|
||||
Cave Spider=Пещерный паук
|
||||
Squid=Кальмар
|
||||
Vex=Досаждатель
|
||||
Evoker=Маг
|
||||
Illusioner=Иллюзор
|
||||
Villager=Житель
|
||||
Vindicator=Поборник
|
||||
Zombie Villager=Зомби-житель
|
||||
Witch=Ведьма
|
||||
Wither=Иссушитель
|
||||
Wolf=Волк
|
||||
Husk=Кадавр
|
||||
Zombie=Зомби
|
||||
Zombie Pigman=Зомби-свиночеловек
|
||||
Iron Horse Armor=Железные доспехи лошади
|
||||
Iron horse armor can be worn by horses to increase their protection from harm a bit.=Железные доспехи лошади, надетые на лошадь, немного защищают её от вреда.
|
||||
Golden Horse Armor=Золотые доспехи лошади
|
||||
Golden horse armor can be worn by horses to increase their protection from harm.=Золотые доспехи лошади, надетые на лошадь, защищают её от вреда.
|
||||
Diamond Horse Armor=Алмазные доспехи лошади
|
||||
Diamond horse armor can be worn by horses to greatly increase their protection from harm.=Алмазные доспехи лошади, надетые на лошадь, отлично защищают её от вреда.
|
||||
Place it on a horse to put on the horse armor. Donkeys and mules can't wear horse armor.=Поместите это на лошадь, чтобы одеть лошадь в доспехи. Ослики и мулы не могут носить лошадиные доспехи.
|
||||
Farmer=Фермер
|
||||
Fisherman=Рыбак
|
||||
Fletcher=Лучник
|
||||
Shepherd=Пастух
|
||||
Librarian=Библиотекарь
|
||||
Cartographer=Картограф
|
||||
Armorer=Бронник
|
||||
Leatherworker=Кожевник
|
||||
Butcher=Мясник
|
||||
Weapon Smith=Оружейник
|
||||
Tool Smith=Инструментальщик
|
||||
Cleric=Церковник
|
||||
Nitwit=Нищий
|
||||
Protects you from death while wielding it=Защищает вас от смерти, пока вы владеете им
|
|
@ -32,8 +32,6 @@ local ocelot = {
|
|||
can_despawn = true,
|
||||
hp_min = 10,
|
||||
hp_max = 10,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 0.69, 0.3},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_cat.b3d",
|
||||
|
@ -43,7 +41,6 @@ local ocelot = {
|
|||
walk_chance = default_walk_chance,
|
||||
walk_velocity = 1,
|
||||
run_velocity = 3,
|
||||
follow_velocity = 1,
|
||||
floats = 1,
|
||||
runaway = true,
|
||||
fall_damage = 0,
|
||||
|
@ -51,12 +48,11 @@ local ocelot = {
|
|||
sounds = {
|
||||
damage = "mobs_mc_ocelot_hurt",
|
||||
death = "mobs_mc_ocelot_hurt",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
speed_normal = 25,
|
||||
run_speed = 50,
|
||||
speed_run = 50,
|
||||
stand_start = 0,
|
||||
stand_end = 0,
|
||||
walk_start = 0,
|
||||
|
@ -109,14 +105,12 @@ cat.order = "roam" -- "sit" or "roam"
|
|||
cat.owner_loyal = true
|
||||
cat.tamed = true
|
||||
cat.runaway = false
|
||||
cat.follow_velocity = 2.4
|
||||
-- Automatically teleport cat to owner
|
||||
cat.do_custom = mobs_mc.make_owner_teleport_function(12)
|
||||
cat.sounds = {
|
||||
random = "mobs_mc_cat_idle",
|
||||
damage = "mobs_mc_cat_hiss",
|
||||
death = "mobs_mc_ocelot_hurt",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
}
|
||||
cat.on_rightclick = function(self, clicker)
|
||||
|
|
|
@ -17,53 +17,43 @@ mobs:register_mob("mobs_mc:parrot", {
|
|||
pathfinding = 1,
|
||||
hp_min = 6,
|
||||
hp_max = 6,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_parrot.b3d",
|
||||
textures = {{"mobs_mc_parrot_blue.png"},{"mobs_mc_parrot_green.png"},{"mobs_mc_parrot_grey.png"},{"mobs_mc_parrot_red_blue.png"},{"mobs_mc_parrot_yellow_blue.png"}},
|
||||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
walk_velocity = 3,
|
||||
run_velocity = 5,
|
||||
sounds = {
|
||||
random = "mobs_mc_parrot_random",
|
||||
damage = {name="mobs_mc_parrot_hurt", gain=0.3},
|
||||
death = {name="mobs_mc_parrot_death", gain=0.6},
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
-- TODO: sounds
|
||||
drops = {
|
||||
{name = mobs_mc.items.feather,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 50,
|
||||
walk_speed = 50,
|
||||
fly_speed = 50,
|
||||
stand_start = 30,
|
||||
stand_end = 45,
|
||||
fly_start = 30,
|
||||
fly_end = 45,
|
||||
walk_start = 30,
|
||||
walk_end = 45,
|
||||
-- TODO: actual walk animation
|
||||
--walk_start = 0,
|
||||
--walk_end = 20,
|
||||
|
||||
-- TODO: more unused animations between 45 and 130
|
||||
stand_start = 0,
|
||||
stand_end = 0,
|
||||
walk_start = 0,
|
||||
walk_end = 130,
|
||||
--run_start = 0,
|
||||
--run_end = 20,
|
||||
--fly_start = 30,
|
||||
--fly_end = 45,
|
||||
},
|
||||
walk_chance = 100,
|
||||
fall_damage = 0,
|
||||
fall_speed = -2.25,
|
||||
attack_type = "dogfight",
|
||||
jump = true,
|
||||
jump_height = 4,
|
||||
floats = 1,
|
||||
physical = true,
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
fear_height = 0,
|
||||
fear_height = 4,
|
||||
view_range = 16,
|
||||
follow = mobs_mc.follow.parrot,
|
||||
on_rightclick = function(self, clicker)
|
||||
|
@ -71,7 +61,6 @@ mobs:register_mob("mobs_mc:parrot", {
|
|||
local item = clicker:get_wielded_item()
|
||||
-- Kill parrot if fed with cookie
|
||||
if item:get_name() == mobs_mc.items.cookie then
|
||||
minetest.sound_play("mobs_mc_animal_eat_generic", {object = self.object, max_hear_distance=16}, true)
|
||||
self.health = 0
|
||||
-- Doomed to die
|
||||
self._doomed = true
|
||||
|
@ -90,8 +79,10 @@ mobs:register_mob("mobs_mc:parrot", {
|
|||
|
||||
})
|
||||
|
||||
-- Parrots spawn rarely in jungles. TODO: Also check for jungle *biome*
|
||||
mobs:spawn_specific("mobs_mc:parrot", {"mcl_core:jungletree", "mcl_core:jungleleaves"}, {"air"}, 0, minetest.LIGHT_MAX+1, 7, 30000, 1, mobs_mc.spawn_height.water+7, mobs_mc.spawn_height.overworld_max)
|
||||
|
||||
-- Spawn disabled because parrots are not very smart.
|
||||
-- TODO: Re-enable when parrots are finished
|
||||
--mobs:spawn_specific("mobs_mc:parrot", mobs_mc.spawn.jungle, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 30000, 1, mobs_mc.spawn_height.water+1, mobs_mc.spawn_height.overworld_max)
|
||||
|
||||
-- spawn eggs
|
||||
mobs:register_egg("mobs_mc:parrot", S("Parrot"), "mobs_mc_spawn_icon_parrot.png", 0)
|
||||
mobs:register_egg("mobs_mc:parrot", S("Parrot"), "mobs_mc_spawn_icon_parrot.png", 0, true)
|
||||
|
|
|
@ -8,8 +8,6 @@ mobs:register_mob("mobs_mc:pig", {
|
|||
runaway = true,
|
||||
hp_min = 10,
|
||||
hp_max = 10,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
collisionbox = {-0.45, -0.01, -0.45, 0.45, 0.865, 0.45},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_pig.b3d",
|
||||
|
@ -22,26 +20,23 @@ mobs:register_mob("mobs_mc:pig", {
|
|||
makes_footstep_sound = true,
|
||||
walk_velocity = 1,
|
||||
run_velocity = 3,
|
||||
follow_velocity = 3.4,
|
||||
drops = {
|
||||
{name = mobs_mc.items.porkchop_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 3,
|
||||
looting = "common",},
|
||||
max = 3,},
|
||||
},
|
||||
fear_height = 4,
|
||||
sounds = {
|
||||
random = "mobs_pig",
|
||||
death = "mobs_pig_angry",
|
||||
damage = "mobs_pig",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 40,
|
||||
walk_speed = 40,
|
||||
run_speed = 90,
|
||||
run_speed = 50,
|
||||
stand_start = 0,
|
||||
stand_end = 0,
|
||||
walk_start = 0,
|
||||
|
@ -50,7 +45,7 @@ mobs:register_mob("mobs_mc:pig", {
|
|||
run_end = 40,
|
||||
},
|
||||
follow = mobs_mc.follow.pig,
|
||||
view_range = 8,
|
||||
view_range = 5,
|
||||
do_custom = function(self, dtime)
|
||||
|
||||
-- set needed values if not already present
|
||||
|
@ -83,6 +78,7 @@ mobs:register_mob("mobs_mc:pig", {
|
|||
if self.driver then
|
||||
mobs.detach(self.driver, {x = 1, y = 0, z = 1})
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
|
|
|
@ -14,8 +14,6 @@ mobs:register_mob("mobs_mc:polar_bear", {
|
|||
passive = false,
|
||||
hp_min = 30,
|
||||
hp_max = 30,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
breath_max = -1,
|
||||
collisionbox = {-0.7, -0.01, -0.7, 0.7, 1.39, 0.7},
|
||||
visual = "mesh",
|
||||
|
@ -36,26 +34,17 @@ mobs:register_mob("mobs_mc:polar_bear", {
|
|||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 2,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
-- 1/4 to drop raw salmon
|
||||
{name = mobs_mc.items.salmon_raw,
|
||||
chance = 4,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
|
||||
},
|
||||
floats = 1,
|
||||
fear_height = 4,
|
||||
sounds = {
|
||||
random = "mobs_mc_bear_random",
|
||||
attack = "mobs_mc_bear_attack",
|
||||
damage = "mobs_mc_bear_hurt",
|
||||
death = "mobs_mc_bear_death",
|
||||
war_cry = "mobs_mc_bear_growl",
|
||||
distance = 16,
|
||||
},
|
||||
-- TODO: sounds
|
||||
animation = {
|
||||
speed_normal = 25, speed_run = 50,
|
||||
stand_start = 0, stand_end = 0,
|
||||
|
|
|
@ -10,8 +10,6 @@ local rabbit = {
|
|||
|
||||
hp_min = 3,
|
||||
hp_max = 3,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.49, 0.2},
|
||||
|
||||
visual = "mesh",
|
||||
|
@ -25,25 +23,19 @@ local rabbit = {
|
|||
{"mobs_mc_rabbit_black.png"},
|
||||
},
|
||||
visual_size = {x=1.5, y=1.5},
|
||||
sounds = {
|
||||
random = "mobs_mc_rabbit_random",
|
||||
damage = "mobs_mc_rabbit_hurt",
|
||||
death = "mobs_mc_rabbit_death",
|
||||
attack = "mobs_mc_rabbit_attack",
|
||||
eat = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
-- TODO: sounds: random, damage, death
|
||||
makes_footstep_sound = false,
|
||||
walk_velocity = 1,
|
||||
run_velocity = 3.7,
|
||||
follow_velocity = 1.1,
|
||||
floats = 1,
|
||||
runaway = true,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1, looting = "common",},
|
||||
{name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1, looting = "common",},
|
||||
{name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1, looting = "rare", looting_factor = 0.03,},
|
||||
{name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1},
|
||||
{name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1},
|
||||
{name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1},
|
||||
-- TODO: Drop rabbit's foot when it's useful
|
||||
--{name = mobs_mc.items.rabbit_foot, chance = 10, min = 1, max = 1},
|
||||
},
|
||||
fear_height = 4,
|
||||
animation = {
|
||||
|
|
|
@ -47,8 +47,7 @@ mobs:register_mob("mobs_mc:sheep", {
|
|||
spawn_class = "passive",
|
||||
hp_min = 8,
|
||||
hp_max = 8,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
|
||||
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.29, 0.45},
|
||||
|
||||
visual = "mesh",
|
||||
|
@ -63,25 +62,22 @@ mobs:register_mob("mobs_mc:sheep", {
|
|||
{name = mobs_mc.items.mutton_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
{name = colors["unicolor_white"][1],
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
max = 1,},
|
||||
},
|
||||
fear_height = 4,
|
||||
sounds = {
|
||||
random = "mobs_sheep",
|
||||
death = "mobs_sheep",
|
||||
damage = "mobs_sheep",
|
||||
sounds = "mobs_mc_animal_eat_generic",
|
||||
distance = 16,
|
||||
},
|
||||
animation = {
|
||||
speed_normal = 25, run_speed = 65,
|
||||
stand_start = 40, stand_end = 80,
|
||||
speed_normal = 25, speed_run = 50,
|
||||
stand_start = 40, stand_end = 80,
|
||||
walk_start = 0, walk_end = 40,
|
||||
run_start = 0, run_end = 40,
|
||||
},
|
||||
|
@ -160,7 +156,7 @@ mobs:register_mob("mobs_mc:sheep", {
|
|||
if item:get_name() == mobs_mc.items.shears and not self.gotten and not self.child then
|
||||
self.gotten = true
|
||||
local pos = self.object:get_pos()
|
||||
minetest.sound_play("mcl_tools_shears_cut", {pos = pos}, true)
|
||||
minetest.sound_play("shears", {pos = pos}, true)
|
||||
pos.y = pos.y + 0.5
|
||||
if not self.color then
|
||||
self.color = "unicolor_white"
|
||||
|
|
|
@ -21,8 +21,6 @@ mobs:register_mob("mobs_mc:shulker", {
|
|||
passive = false,
|
||||
hp_min = 30,
|
||||
hp_max = 30,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
armor = 150,
|
||||
collisionbox = {-0.5, -0.01, -0.5, 0.5, 0.99, 0.5},
|
||||
visual = "mesh",
|
||||
|
@ -35,11 +33,9 @@ mobs:register_mob("mobs_mc:shulker", {
|
|||
jump = false,
|
||||
drops = {
|
||||
{name = mobs_mc.items.shulker_shell,
|
||||
chance = 2,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0625},
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 25, walk_speed = 25, run_speed = 50, punch_speed = 25,
|
||||
|
@ -79,6 +75,6 @@ mobs:register_arrow("mobs_mc:shulkerbullet", {
|
|||
})
|
||||
|
||||
|
||||
mobs:register_egg("mobs_mc:shulker", S("Shulker"), "mobs_mc_spawn_icon_shulker.png", 0)
|
||||
mobs:register_egg("mobs_mc:shulker", S("Schulker"), "mobs_mc_spawn_icon_shulker.png", 0)
|
||||
|
||||
mobs:spawn_specific("mobs_mc:shulker", mobs_mc.spawn.end_city, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 5000, 2, mobs_mc.spawn_height.end_min, mobs_mc.spawn_height.end_max)
|
||||
|
|
|
@ -12,9 +12,6 @@ mobs:register_mob("mobs_mc:silverfish", {
|
|||
reach = 1,
|
||||
hp_min = 8,
|
||||
hp_max = 8,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
armor = {fleshy = 100, arthropod = 100},
|
||||
collisionbox = {-0.4, -0.01, -0.4, 0.4, 0.44, 0.4},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_silverfish.b3d",
|
||||
|
|
|
@ -17,10 +17,7 @@ local skeleton = {
|
|||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
hp_max = 20,
|
||||
xp_min = 6,
|
||||
xp_max = 6,
|
||||
breath_max = -1,
|
||||
armor = {undead = 100, fleshy = 100},
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.98, 0.3},
|
||||
pathfinding = 1,
|
||||
group_attack = true,
|
||||
|
@ -46,18 +43,15 @@ local skeleton = {
|
|||
{name = mobs_mc.items.arrow,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
{name = mobs_mc.items.bow,
|
||||
chance = 100 / 8.5,
|
||||
chance = 11,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.bone,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
|
||||
-- Head
|
||||
-- TODO: Only drop if killed by charged creeper
|
||||
|
@ -81,7 +75,7 @@ local skeleton = {
|
|||
die_speed = 15,
|
||||
die_loop = false,
|
||||
},
|
||||
ignited_by_sunlight = true,
|
||||
sunlight_damage = 1,
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
attack_type = "dogshoot",
|
||||
|
@ -119,21 +113,12 @@ stray.textures = {
|
|||
-- TODO: different sound (w/ echo)
|
||||
-- TODO: stray's arrow inflicts slowness status
|
||||
table.insert(stray.drops, {
|
||||
name = "mcl_potions:slowness_arrow",
|
||||
-- Chance to drop additional arrow.
|
||||
-- TODO: Should be tipped arrow of slowness
|
||||
name = mobs_mc.items.arrow,
|
||||
chance = 2,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_chance_function = function(lvl)
|
||||
local chance = 0.5
|
||||
for i = 1, lvl do
|
||||
if chance > 1 then
|
||||
return 1
|
||||
end
|
||||
chance = chance + (1 - chance) / 2
|
||||
end
|
||||
return chance
|
||||
end,
|
||||
})
|
||||
|
||||
mobs:register_mob("mobs_mc:stray", stray)
|
||||
|
|
|
@ -14,10 +14,7 @@ mobs:register_mob("mobs_mc:witherskeleton", {
|
|||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
hp_max = 20,
|
||||
xp_min = 6,
|
||||
xp_max = 6,
|
||||
breath_max = -1,
|
||||
armor = {undead = 100, fleshy = 100},
|
||||
pathfinding = 1,
|
||||
group_attack = true,
|
||||
collisionbox = {-0.35, -0.01, -0.35, 0.35, 2.39, 0.35},
|
||||
|
@ -45,20 +42,17 @@ mobs:register_mob("mobs_mc:witherskeleton", {
|
|||
{name = mobs_mc.items.coal,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
max = 1,},
|
||||
{name = mobs_mc.items.bone,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
max = 2,},
|
||||
|
||||
-- Head
|
||||
{name = mobs_mc.items.head_wither_skeleton,
|
||||
chance = 40, -- 2.5% chance
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",},
|
||||
max = 1,},
|
||||
},
|
||||
animation = {
|
||||
stand_start = 0,
|
||||
|
@ -90,7 +84,6 @@ mobs:register_mob("mobs_mc:witherskeleton", {
|
|||
dogshoot_count_max =0.5,
|
||||
fear_height = 4,
|
||||
harmed_by_heal = true,
|
||||
fire_resistant = true,
|
||||
})
|
||||
|
||||
--spawn
|
||||
|
|
|
@ -51,7 +51,6 @@ local spawn_children_on_die = function(child_mob, children_count, spawn_distance
|
|||
end
|
||||
end, children, self.attack)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -63,8 +62,6 @@ local slime_big = {
|
|||
group_attack = { "mobs_mc:slime_big", "mobs_mc:slime_small", "mobs_mc:slime_tiny" },
|
||||
hp_min = 16,
|
||||
hp_max = 16,
|
||||
xp_min = 4,
|
||||
xp_max = 4,
|
||||
collisionbox = {-1.02, -0.01, -1.02, 1.02, 2.03, 1.02},
|
||||
visual_size = {x=12.5, y=12.5},
|
||||
textures = {{"mobs_mc_slime.png"}},
|
||||
|
@ -108,9 +105,7 @@ local slime_big = {
|
|||
jump_height = 5.2,
|
||||
fear_height = 0,
|
||||
spawn_small_alternative = "mobs_mc:slime_small",
|
||||
on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5),
|
||||
fire_resistant = true,
|
||||
use_texture_alpha = true,
|
||||
on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5)
|
||||
}
|
||||
mobs:register_mob("mobs_mc:slime_big", slime_big)
|
||||
|
||||
|
@ -118,8 +113,6 @@ local slime_small = table.copy(slime_big)
|
|||
slime_small.sounds.base_pitch = 1.15
|
||||
slime_small.hp_min = 4
|
||||
slime_small.hp_max = 4
|
||||
slime_small.xp_min = 2
|
||||
slime_small.xp_max = 2
|
||||
slime_small.collisionbox = {-0.51, -0.01, -0.51, 0.51, 1.00, 0.51}
|
||||
slime_small.visual_size = {x=6.25, y=6.25}
|
||||
slime_small.damage = 3
|
||||
|
@ -135,8 +128,6 @@ local slime_tiny = table.copy(slime_big)
|
|||
slime_tiny.sounds.base_pitch = 1.3
|
||||
slime_tiny.hp_min = 1
|
||||
slime_tiny.hp_max = 1
|
||||
slime_tiny.xp_min = 1
|
||||
slime_tiny.xp_max = 1
|
||||
slime_tiny.collisionbox = {-0.2505, -0.01, -0.2505, 0.2505, 0.50, 0.2505}
|
||||
slime_tiny.visual_size = {x=3.125, y=3.125}
|
||||
slime_tiny.damage = 0
|
||||
|
@ -169,8 +160,6 @@ local magma_cube_big = {
|
|||
spawn_class = "hostile",
|
||||
hp_min = 16,
|
||||
hp_max = 16,
|
||||
xp_min = 4,
|
||||
xp_max = 4,
|
||||
collisionbox = {-1.02, -0.01, -1.02, 1.02, 2.03, 1.02},
|
||||
visual_size = {x=12.5, y=12.5},
|
||||
textures = {{ "mobs_mc_magmacube.png" }},
|
||||
|
@ -187,7 +176,7 @@ local magma_cube_big = {
|
|||
run_velocity = 4,
|
||||
damage = 6,
|
||||
reach = 3,
|
||||
armor = 53,
|
||||
armor = 40,
|
||||
drops = {
|
||||
{name = mobs_mc.items.magma_cream,
|
||||
chance = 4,
|
||||
|
@ -222,8 +211,7 @@ local magma_cube_big = {
|
|||
walk_chance = 0,
|
||||
fear_height = 0,
|
||||
spawn_small_alternative = "mobs_mc:magma_cube_small",
|
||||
on_die = spawn_children_on_die("mobs_mc:magma_cube_small", 3, 0.8, 1.5),
|
||||
fire_resistant = true,
|
||||
on_die = spawn_children_on_die("mobs_mc:magma_cube_small", 3, 0.8, 1.5)
|
||||
}
|
||||
mobs:register_mob("mobs_mc:magma_cube_big", magma_cube_big)
|
||||
|
||||
|
@ -232,8 +220,6 @@ magma_cube_small.sounds.jump = "mobs_mc_magma_cube_small"
|
|||
magma_cube_small.sounds.death = "mobs_mc_magma_cube_small"
|
||||
magma_cube_small.hp_min = 4
|
||||
magma_cube_small.hp_max = 4
|
||||
magma_cube_small.xp_min = 2
|
||||
magma_cube_small.xp_max = 2
|
||||
magma_cube_small.collisionbox = {-0.51, -0.01, -0.51, 0.51, 1.00, 0.51}
|
||||
magma_cube_small.visual_size = {x=6.25, y=6.25}
|
||||
magma_cube_small.damage = 3
|
||||
|
@ -243,7 +229,7 @@ magma_cube_small.run_velocity = 2.6
|
|||
magma_cube_small.jump_height = 6
|
||||
magma_cube_small.damage = 4
|
||||
magma_cube_small.reach = 2.75
|
||||
magma_cube_small.armor = 66
|
||||
magma_cube_small.armor = 70
|
||||
magma_cube_small.spawn_small_alternative = "mobs_mc:magma_cube_tiny"
|
||||
magma_cube_small.on_die = spawn_children_on_die("mobs_mc:magma_cube_tiny", 4, 0.6, 1.0)
|
||||
mobs:register_mob("mobs_mc:magma_cube_small", magma_cube_small)
|
||||
|
@ -254,8 +240,6 @@ magma_cube_tiny.sounds.death = "mobs_mc_magma_cube_small"
|
|||
magma_cube_tiny.sounds.base_pitch = 1.25
|
||||
magma_cube_tiny.hp_min = 1
|
||||
magma_cube_tiny.hp_max = 1
|
||||
magma_cube_tiny.xp_min = 1
|
||||
magma_cube_tiny.xp_max = 1
|
||||
magma_cube_tiny.collisionbox = {-0.2505, -0.01, -0.2505, 0.2505, 0.50, 0.2505}
|
||||
magma_cube_tiny.visual_size = {x=3.125, y=3.125}
|
||||
magma_cube_tiny.walk_velocity = 1.02
|
||||
|
@ -263,7 +247,7 @@ magma_cube_tiny.run_velocity = 1.02
|
|||
magma_cube_tiny.jump_height = 4
|
||||
magma_cube_tiny.damage = 3
|
||||
magma_cube_tiny.reach = 2.5
|
||||
magma_cube_tiny.armor = 50
|
||||
magma_cube_tiny.armor = 85
|
||||
magma_cube_tiny.drops = {}
|
||||
magma_cube_tiny.spawn_small_alternative = nil
|
||||
magma_cube_tiny.on_die = nil
|
||||
|
|
|
@ -31,16 +31,11 @@ mobs:register_mob("mobs_mc:snowman", {
|
|||
fall_damage = 0,
|
||||
water_damage = 4,
|
||||
rain_damage = 4,
|
||||
armor = { fleshy = 100, water_vulnerable = 100 },
|
||||
attacks_monsters = true,
|
||||
collisionbox = {-0.35, -0.01, -0.35, 0.35, 1.89, 0.35},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_snowman.b3d",
|
||||
sounds = {
|
||||
damage = { name = "mobs_mc_snowman_hurt", gain = 0.2 },
|
||||
death = { name = "mobs_mc_snowman_death", gain = 0.25 },
|
||||
distance = 16,
|
||||
},
|
||||
-- TODO: sounds: damage, death
|
||||
textures = {
|
||||
"mobs_mc_snowman.png", --snowman texture
|
||||
"farming_pumpkin_side.png", --top
|
||||
|
@ -78,7 +73,7 @@ mobs:register_mob("mobs_mc:snowman", {
|
|||
run_end = 20,
|
||||
die_start = 40,
|
||||
die_end = 50,
|
||||
die_speed = 15,
|
||||
die_speed = 25,
|
||||
die_loop = false,
|
||||
},
|
||||
do_custom = function(self, dtime)
|
||||
|
@ -121,7 +116,7 @@ mobs:register_mob("mobs_mc:snowman", {
|
|||
})
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
minetest.sound_play("mcl_tools_shears_cut", {pos = pos}, true)
|
||||
minetest.sound_play("shears", {pos = pos}, true)
|
||||
|
||||
-- Wear out
|
||||
if not minetest.is_creative_enabled(clicker:get_player_name()) then
|
||||
|
@ -132,26 +127,6 @@ mobs:register_mob("mobs_mc:snowman", {
|
|||
end,
|
||||
})
|
||||
|
||||
local summon_particles = function(obj)
|
||||
local lua = obj:get_luaentity()
|
||||
local min = {x=lua.collisionbox[1], y=lua.collisionbox[2], z=lua.collisionbox[3]}
|
||||
local max = {x=lua.collisionbox[4], y=lua.collisionbox[5], z=lua.collisionbox[6]}
|
||||
local pos = obj:get_pos()
|
||||
minetest.add_particlespawner({
|
||||
amount = 60,
|
||||
time = 0.1,
|
||||
minpos = vector.add(pos, min),
|
||||
maxpos = vector.add(pos, max),
|
||||
minvel = {x = -0.1, y = -0.1, z = -0.1},
|
||||
maxvel = {x = 0.1, y = 0.1, z = 0.1},
|
||||
minexptime = 1.0,
|
||||
maxexptime = 2.0,
|
||||
minsize = 2.0,
|
||||
maxsize = 3.0,
|
||||
texture = "mcl_particles_smoke.png",
|
||||
})
|
||||
end
|
||||
|
||||
-- This is to be called when a pumpkin or jack'o lantern has been placed. Recommended: In the on_construct function
|
||||
-- of the node.
|
||||
-- This summons a snow golen when pos is next to a row of two snow blocks.
|
||||
|
@ -181,10 +156,7 @@ mobs_mc.tools.check_snow_golem_summon = function(pos)
|
|||
core.check_for_falling(pos)
|
||||
core.check_for_falling(b1)
|
||||
core.check_for_falling(b2)
|
||||
local obj = minetest.add_entity(place, "mobs_mc:snowman")
|
||||
if obj then
|
||||
summon_particles(obj)
|
||||
end
|
||||
minetest.add_entity(place, "mobs_mc:snowman")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
|