54 Commits

Author SHA1 Message Date
AntumDeluge
e35dd34462 Add 'mobs_redo' compatibility (WIP) 2017-08-08 02:31:05 -07:00
AntumDeluge
c364ad6e85 Use 'or' to optimize 'settings:get_bool' 2017-07-28 17:12:54 -07:00
AntumDeluge
38c6e79718 Call 'core.*' instead of 'minetest.*' 2017-07-28 17:10:57 -07:00
AntumDeluge
7dcc78393a settings: Use 'enable_debug_mods' instead of 'sneeker.debug' 2017-06-27 17:29:04 -07:00
AntumDeluge
a56b9c2ce9 User alternate message if spawn chance is less than 1% 2017-06-07 20:33:46 -07:00
AntumDeluge
59253fb4c1 Fix 'spawn_cap' 2017-06-07 16:44:07 -07:00
AntumDeluge
0ff4681d5e Fix setting 'sneeker.debug' to 'false' by default 2017-06-06 20:50:12 -07:00
AntumDeluge
8d144e47db Replace deprecated methods:
- 'setting_get' with 'settings:get'
- 'setting_getbool' with 'settings:get_bool'
2017-06-06 20:48:23 -07:00
AntumDeluge
9e1b11a52c Fix converting setting types to integer 2017-06-04 11:59:15 -07:00
AntumDeluge
e948a58c3d Set default maximum spawn to 10 2017-06-01 15:26:45 -07:00
AntumDeluge
046e7d5e8c Lower spawn rate & chance 2017-06-01 11:58:41 -07:00
AntumDeluge
468d2a7a2a Make 'spawn_cap' local to 'spawn.lua' 2017-05-31 12:01:44 -07:00
AntumDeluge
73b221c13f Make 'spawn_maxlight' local to 'spawn.lua' 2017-05-31 11:57:20 -07:00
AntumDeluge
555110bb82 Set 'spawn_maxlight' to 5 for lower spawn rate 2017-05-31 11:53:06 -07:00
AntumDeluge
258d366b26 Call 'setting_getbool' for 'sneeker.debug' option 2017-05-29 15:02:46 -07:00
AntumDeluge
b69cc98d39 Change 'spawn_maxlight' default value to '7' 2017-05-29 02:58:34 -07:00
AntumDeluge
2b0871207f Change 'spawn_interval' default to 2 minutes (120) 2017-05-29 02:57:56 -07:00
AntumDeluge
6605ac1545 Change 'spawn_chance' default to '2' (1/2 or 50%) 2017-05-29 02:57:06 -07:00
AntumDeluge
822d73920d Add more debugging output 2017-05-29 02:55:13 -07:00
AntumDeluge
b7f0f34a41 Fix finding number of active entities in world 2017-05-29 02:54:14 -07:00
AntumDeluge
84f51c893b Don't set local 'spawnit' 2017-05-29 02:53:20 -07:00
AntumDeluge
85e849767f Add method 'sneeker.get_pos_string':
Returns x, y, z coordinates in a string.
2017-05-29 02:49:02 -07:00
AntumDeluge
8485715aba Add debugging output in case of denied spawn 2017-05-29 01:44:06 -07:00
AntumDeluge
ea60b5fe9b Fix global name:
- 'sneeker' not 'sneaker'
2017-05-29 01:29:08 -07:00
AntumDeluge
2ddc96de06 Minor edit to log message 2017-05-29 01:25:51 -07:00
AntumDeluge
a2ce6cfea8 Changes to 'sneeker.log' method:
Only log message if minetest setting 'log_mods' is 'true'.
2017-05-29 01:25:28 -07:00
AntumDeluge
b165e45d92 Change debug message in 'sneeker.log_debug' 2017-05-29 01:16:02 -07:00
AntumDeluge
677622d307 Add debug message to display in log when turned on 2017-05-29 01:08:02 -07:00
AntumDeluge
0ad9f2bd2a Put node light in local variable & add debugging output 2017-05-29 01:01:14 -07:00
AntumDeluge
05019c9d7d Use setting 'sneeker.spawn_maxlight' to determine node light for spawn 2017-05-29 01:00:39 -07:00
AntumDeluge
1dc5b92314 Add method 'sneaker.spawn' to spawn entity 2017-05-29 00:58:55 -07:00
AntumDeluge
d336800b35 Do not spawn if spawn cap is reached 2017-05-29 00:14:26 -07:00
AntumDeluge
398971d08c Put mob & spawnegg names in 'sneeker' attributes 2017-05-29 00:06:18 -07:00
AntumDeluge
d777d4f000 Set spawn cap at 25 2017-05-28 23:59:59 -07:00
AntumDeluge
9d7c566fdb Change settings naming convention from 'sneeker_*' to 'sneeker.*' 2017-05-28 18:32:29 -07:00
AntumDeluge
b5c7aeb15d Re-label to 'sneeker' 2017-05-27 19:54:26 -07:00
AntumDeluge
f50c7f37ca Move settings variables & functions:
- Settings to 'settings.lua'
- Functions to 'functions.lua'
2017-05-27 19:30:56 -07:00
AntumDeluge
604eb77dc7 Add debugging setting & log method 2017-05-27 19:20:00 -07:00
AntumDeluge
3f835fa65d Add logging messages 2017-05-27 19:15:23 -07:00
AntumDeluge
fa0b50491f settingtypes.txt: Add 'sneaker_spawn_cap' 2017-05-27 19:14:35 -07:00
AntumDeluge
46a23df877 Change spawn rate:
- Use settings file to set 'chance' & 'interval'
- Set spawn chance to 1/18000 (18000)
- Set spawn interval to 40 minutes (2400)
2017-05-27 19:13:47 -07:00
AntumDeluge
85ca164e14 Add variable 'sneaker.spawn_cap':
Will set maximun number of sneakers that can be spawned in world at one
time.
2017-05-27 19:09:14 -07:00
AntumDeluge
930d52cb3d Remove unnecessary variable 'time_sec' 2017-05-27 19:07:41 -07:00
AntumDeluge
2712d7119c Add 'sneaker.log' method 2017-05-27 19:07:14 -07:00
AntumDeluge
f6eca4002a Use 'setting_get*' methods instead of 'settings:get*':
Compatibility with 0.4.15 server.
2017-05-27 18:04:30 -07:00
AntumDeluge
b8a2e98ea0 Set license for new code as CC0 2017-05-27 17:36:45 -07:00
AntumDeluge
102c9d9266 Rename 'LICENSE.md' to 'LICENSE-wtfpl.txt' 2017-05-27 17:30:14 -07:00
AntumDeluge
56033e8988 Set variables 'sneaker.modname' & 'sneaker.modpath' 2017-05-27 17:26:42 -07:00
AntumDeluge
e8a37511ea Replace double-quoted strings with single-quoted 2017-05-27 17:26:10 -07:00
AntumDeluge
83c26a3a41 Relabel to 'sneaker' 2017-05-27 17:23:59 -07:00
AntumDeluge
14f9c3c6b3 Replace deprecated methods:
- 'setting_get' with 'settings:get'
- 'setting_getbool' with 'settings:get_bool'
2017-05-15 15:23:18 -07:00
AntumDeluge
299b12b5a4 Run spawn function every 20 minutes 2017-05-15 15:23:18 -07:00
AntumDeluge
07d7745455 Use 'spawneggs' & 'tnt' to craft 'creeper:spawnegg' 2017-05-15 15:23:18 -07:00
AntumDeluge
3cc1158417 Ignore Eclipse project files & directories 2017-05-15 15:23:18 -07:00
15 changed files with 689 additions and 803 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
## Eclipse project files & directories
.project
.settings

View File

@@ -1,8 +0,0 @@
1.0
- Forked & renamed from Rui's original "creeper" mod.
- Updated for Minetest 5.x API.
- Changed to MIT license.
- Ported to Creatures Revived (cmer) engine.
- Spawn on more types of nodes.
- Spawn on "nether:rack" if nether mod available.

13
LICENSE-wtfpl.txt Normal file
View File

@@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@@ -1,21 +1,121 @@
The MIT License (MIT) Creative Commons Legal Code
Copyright © 2021 Jordan Irwin (AntumDeluge) CC0 1.0 Universal
Permission is hereby granted, free of charge, to any person obtaining a copy of CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
this software and associated documentation files (the "Software"), to deal in LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
the Software without restriction, including without limitation the rights to ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
of the Software, and to permit persons to whom the Software is furnished to do REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
so, subject to the following conditions: PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
The above copyright notice and this permission notice shall be included in Statement of Purpose
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR The laws of most jurisdictions throughout the world automatically confer
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, exclusive Copyright and Related Rights (defined below) upon the creator
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE and subsequent owner(s) (each and all, an "owner") of an original work of
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER authorship and/or a database (each, a "Work").
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE Certain owners wish to permanently relinquish those rights to a Work for
SOFTWARE. the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@@ -1,51 +1,17 @@
## Sneeker mod for Minetest # Sneeker mobile mod for Minetest
--- Adds some explosive nuisance.
### Description:
An explosive nuisance for [Minetest](http://minetest.net/). ## Forum Topic
![screenshot](screenshot.png) - Original thread: https://forum.minetest.net/viewtopic.php?t=11891
--- ## License
### Licensing:
- **Code:** [MIT](LICENSE.txt) - **Code:**
- Original by Rui: WTFPL - Original by Rui: [WTFPL][lic.wtfpl]
- AntumDeluge: [CC0][lic.cc0]
---
### Usage:
Settings: [lic.cc0]: LICENSE.txt
- ***sneeker.spawn_chance*** [lic.wtfpl]: LICENSE-wtfpl.txt
- Sets possibility for spawn.
- type: int
- default: 10000
- ***sneeker.spawn_interval***
- Sets frequency of spawn chance.
- type: int
- default: 240 (4 minutes)
- ***sneeker.spawn_minlight***
- Sets the minimum light that a node must have for spawn to occur.
- type: int
- default: 0
- ***sneeker.spawn_maxlight***
- Sets the maximum light that a node can have for spawn to occur.
- type: int
- default: 9
- ***sneeker.spawn_minheight***
- Sets the maximum light that a node can have for spawn to occur.
- type: int
- default: -31000
- ***sneeker.spawn_maxheight***
- Sets the lowest position at which sneeker can spawn.
- type: int
- default 31000
---
### Links:
- [Original forum thread](https://forum.minetest.net/viewtopic.php?t=11891)
- [Git repo](https://github.com/AntumMT/mod-sneeker)
- [Changelog](CHANGES.txt)
- [TODO](TODO.txt)

View File

@@ -1,5 +0,0 @@
TODO:
- fix walk logic to stop before exploding
- fix sound playthrough
- remove unused setting "sneeker.spawn_cap"

4
depends.txt Normal file
View File

@@ -0,0 +1,4 @@
default
mobs?
spawneggs?
tnt?

1
description.txt Normal file
View File

@@ -0,0 +1 @@
Adds some explosive nuisance.

View File

@@ -1,13 +1,30 @@
-- Functions for sneeker mod -- Functions for sneeker mod
local log_mods = core.settings:get_bool('log_mods')
-- Displays a message in log output
function sneeker.log(message)
if log_mods then
core.log('action', '[' .. sneeker.modname .. '] ' .. message)
end
end
-- Displays a message in log output only if 'sneeker.debug' is set to 'true'
function sneeker.log_debug(message)
if sneeker.debug then
sneeker.log('DEBUG: ' .. message)
end
end
-- Spawns a sneeker entity -- Spawns a sneeker entity
function sneeker.spawn(pos) function sneeker.spawn(pos)
core.add_entity(pos, sneeker.mob_name) core.add_entity(pos, sneeker.mob_name)
sneeker.log("debug", "Spawned entity \"" .. sneeker.mob_name .. "\" at " .. tostring(pos.x) .. "," .. tostring(pos.y)) sneeker.log_debug('Spawned entity "' .. sneeker.mob_name .. '" at ' .. tostring(pos.x) .. ',' .. tostring(pos.y))
end end
-- Retrieves pos coordinates in string value -- Retrieves pos coordinates in string value
function sneeker.get_pos_string(pos) function sneeker.get_pos_string(pos)
return "x=" .. tostring(pos.x) .. ", y=" .. tostring(pos.y) .. ", z=" .. tostring(pos.z) return 'x=' .. tostring(pos.x) .. ', y=' .. tostring(pos.y) .. ', z=' .. tostring(pos.z)
end end

944
init.lua
View File

@@ -1,560 +1,384 @@
-- Original code by Rui: WTFPL
sneeker = {}
sneeker.modname = core.get_current_modname()
sneeker.modpath = core.get_modpath(sneeker.modname) sneeker = {}
sneeker.modname = core.get_current_modname()
dofile(sneeker.modpath .. "/settings.lua") sneeker.modpath = core.get_modpath(sneeker.modname)
sneeker.log = function(lvl, msg) if core.settings:get_bool('log_mods') then
if lvl == "debug" and not sneeker.debug then return end core.log('action', 'Loading mod "' .. sneeker.modname .. '" ...')
end
if not msg then
msg = lvl dofile(sneeker.modpath .. '/settings.lua')
lvl = nil dofile(sneeker.modpath .. '/functions.lua')
end
sneeker.log_debug('Debugging is on')
msg = "[" .. sneeker.modname .. "] " .. msg
if lvl == "debug" then sneeker.mob_name = sneeker.modname .. ':' .. sneeker.modname
msg = "[DEBUG] " .. msg sneeker.spawnegg_name = sneeker.modname .. ':spawnegg'
end
local scripts = {
if not lvl then 'tnt_function',
core.log(msg) 'spawn',
else }
core.log(lvl, msg)
end for I in pairs(scripts) do
end dofile(sneeker.modpath .. '/' .. scripts[I] .. '.lua')
end
sneeker.log("debug", "Debugging is on")
local radius = tonumber(core.settings:get('tnt_radius') or 3)
if core.settings:get_bool("log_mods") then
core.log("action", "Loading mod \"" .. sneeker.modname .. "\" ...")
end local def = {
hp_max = 20,
sneeker.mob_name = "sneeker:sneeker" physical = true,
local old_spawnegg_name = "sneeker:spawnegg" collisionbox = {-0.25, -0.7, -0.25, 0.25, 0.8, 0.25},
visual = 'mesh',
local scripts = { mesh = 'character.b3d',
"functions", textures = {'sneeker.png'},
"tnt_function", makes_footstep_sound = false,
--"spawn", jump_height = 5,
} }
for _, script in ipairs(scripts) do
dofile(sneeker.modpath .. "/" .. script .. ".lua")
end if core.global_exists('mobs') then
def.type = 'monster'
--[[ def.walk_velocity = 1.5
local function jump(self, pos, direction) def.knock_back = 2
local velocity = self.object:get_velocity() def.attack_type = 'explode'
if core.registered_nodes[core.get_node(pos).name].climbable then def.explosion_radius = radius
self.object:set_velocity({x=velocity.x, y=4, z=velocity.z}) --[[
return def.on_blast = function(object, damage)
end explode(object)
end
local spos = {x=pos.x+direction.x, y=pos.y, z=pos.z+direction.z} ]]
local node = core.get_node_or_nil(spos) def.animation = {
spos.y = spos.y+1 stand_start = 0,
local node2 = core.get_node_or_nil(spos) stand_end = 79,
local def, def2 = {} stand_speed = 30,
if node and node.name then walk_start = 168,
def = core.registered_items[node.name] walk_end = 187,
end walk_speek = 30,
if node2 and node2.name then }
def2 = core.registered_items[node2.name] def.sounds = {
end explode = 'sneeker_explode',
if def and def.walkable distance = 128,
and def2 and not def2.walkable }
and def.drawtype ~= "fencelike" then
self.object:set_velocity({ mobs:register_mob(sneeker.mob_name, def)
x = velocity.x*2.2, -- TODO: Add alias
y = self.jump_height, else
z = velocity.z*2.2 def.walk_speed = 1.5
}) def.knockback_level = 2
end def.animation = {
end stand_START = 0,
stand_END = 79,
local function random_turn(self) walk_START = 168,
if self.turn_timer > math.random(2, 5) then walk_END = 187,
local select_turn = math.random(1, 3) }
if select_turn == 1 then def.animation_speed = 30
self.turn = "left"
elseif select_turn == 2 then
self.turn = "right" local function jump(self,pos,direction)
elseif select_turn == 3 then local velocity = self.object:getvelocity()
self.turn = "straight" if core.registered_nodes[core.get_node(pos).name].climbable then
end self.object:setvelocity({x=velocity.x,y=4,z=velocity.z})
self.turn_timer = 0 return
self.turn_speed = 0.05*math.random() end
end
end local spos = {x=pos.x+direction.x,y=pos.y,z=pos.z+direction.z}
local node = core.get_node_or_nil(spos)
local def = { spos.y = spos.y+1
hp_max = 20, local node2 = core.get_node_or_nil(spos)
physical = true, local def,def2 = {}
collisionbox = {-0.25, -0.7, -0.25, 0.25, 0.8, 0.25}, if node and node.name then
visual = "mesh", def = core.registered_items[node.name]
mesh = "character.b3d", end
textures = {"sneeker.png"}, if node2 and node2.name then
makes_footstep_sound = false, def2 = core.registered_items[node2.name]
end
-- Original if def and def.walkable
animation = { and def2 and not def2.walkable
stand_START = 0, and def.drawtype ~= 'fencelike' then
stand_END = 79, self.object:setvelocity({
walk_START = 168, x=velocity.x*2.2,
walk_END = 187 y=self.jump_height,
}, z=velocity.z*2.2
walk_speed = 1.5, })
jump_height = 5, end
animation_speed = 30, end
knockback_level = 2
}
]] local function random_turn(self)
if self.turn_timer > math.random(2,5) then
local sneeker_on_activate = function(self, staticdata) local select_turn = math.random(1,3)
--[[ if select_turn == 1 then
self.yaw = 0 self.turn = 'left'
self.anim = 1 elseif select_turn == 2 then
]] self.turn = 'right'
self.timer = 0 elseif select_turn == 3 then
self.visualx = 1 self.turn = 'straight'
--[[ end
self.jump_timer = 0 self.turn_timer = 0
self.turn_timer = 0 self.turn_speed = 0.05*math.random()
self.turn_speed = 0 end
]] end
self.powered = false
--[[
self.knockback = false def.on_activate = function(self,staticdata)
self.state = math.random(1, 2) self.yaw = 0
self.old_y = self.object:get_pos().y self.anim = 1
]] self.timer = 0
self.visualx = 1
local data = core.deserialize(staticdata) self.jump_timer = 0
if data and type(data) == "table" then self.turn_timer = 0
if data.powered == true then self.turn_speed = 0
self.powered = true self.powered = false
self.object:set_properties({textures = {"sneeker_powered.png"}}) self.knockback = false
end self.state = math.random(1,2)
else self.old_y = self.object:getpos().y
if math.random(0, 20) == 20 then
self.powered = true local data = core.deserialize(staticdata)
self.object:set_properties({textures = {"sneeker_powered.png"}}) if data and type(data) == 'table' then
end if data.powered == true then
end self.powered = true
end self.object:set_properties({textures = {'sneeker_powered.png'}})
end
local function isnan(n) else
return tostring(n) == tostring((-1)^.5) if math.random(0,20) == 20 then
end self.powered = true
self.object:set_properties({textures = {'sneeker_powered.png'}})
local sneeker_on_step = function(self, dtime) end
if self.stunned then return false end end
end
local pos = self.object:get_pos()
local inside = core.get_objects_inside_radius(pos, 10)
local velocity = self.object:get_velocity() def.on_step = function(self, dtime)
if self.knockback then
self.timer = self.timer+0.01 return
end
if self.mode == "follow" and self.visualx < 2 then
if not self.hiss then local ANIM_STAND = 1
core.sound_play("sneeker_hiss", {pos=pos, gain=1.5, max_hear_distance=2*64}) local ANIM_WALK = 2
end
self.visualx = self.visualx+0.05 local pos = self.object:getpos()
self.object:set_properties({ local yaw = self.object:getyaw()
visual_size = {x=self.visualx, y=1} local inside = core.get_objects_inside_radius(pos,10)
}) local walk_speed = self.walk_speed
self.hiss = true local animation = self.animation
elseif self.visualx > 1 then local anim_speed = self.animation_speed
self.visualx = self.visualx-0.05 local velocity = self.object:getvelocity()
self.object:set_properties({
visual_size = {x=self.visualx, y=1} self.timer = self.timer+0.01
}) self.turn_timer = self.turn_timer+0.01
self.hiss = false self.jump_timer = self.jump_timer+0.01
end
if not self.chase
for _, object in ipairs(inside) do and self.timer > math.random(2,5) then
if object:is_player() then if math.random() > 0.8 then
self.mode = "follow" self.state = 'stand'
end else
end self.state = 'walk'
end
if self.mode == "follow" then self.timer = 0
local inside_2 = core.get_objects_inside_radius(pos, 2) end
-- boom if self.turn == 'right' then
if #inside_2 ~= 0 then self.yaw = self.yaw+self.turn_speed
for _, object in ipairs(inside_2) do self.object:setyaw(self.yaw)
if object:is_player() and object:get_hp() ~= 0 then elseif self.turn == 'left' then
if self.visualx >= 2 then self.yaw = self.yaw-self.turn_speed
self.object:remove() self.object:setyaw(self.yaw)
sneeker.boom(pos, self.powered) end
core.sound_play("sneeker_explode", {pos=pos, gain=1.5, max_hear_distance=2*64})
return true if self.chase and self.visualx < 2 then
end if self.hiss == false then
end core.sound_play('sneeker_hiss',{pos=pos,gain=1.5,max_hear_distance=2*64})
end end
end self.visualx = self.visualx+0.05
self.object:set_properties({
if #inside > 0 then visual_size = {x=self.visualx,y=1}
for _, object in ipairs(inside) do })
if object:is_player() and object:get_hp() ~= 0 then self.hiss = true
if #inside_2 > 0 then elseif self.visualx > 1 then
for _, object in ipairs(inside_2) do self.visualx = self.visualx-0.05
-- Stop move self.object:set_properties({
if object:is_player() then visual_size = {x=self.visualx,y=1}
--[[ })
if self.anim ~= ANIM_STAND then self.hiss = false
self.object:set_animation({x=animation.stand_START, y=animation.stand_END}, anim_speed, 0) end
self.anim = ANIM_STAND
end self.chase = false
]]
--self.object:set_velocity({x=0, y=velocity.y, z=0}) for _,object in ipairs(inside) do
return false if object:is_player() then
end self.state = 'chase'
end end
end end
-- follow player if self.state == 'stand' then
local ppos = object:get_pos() if self.anim ~= ANIM_STAND then
self.vec = {x=ppos.x-pos.x, y=ppos.y-pos.y, z=ppos.z-pos.z} self.object:set_animation({x=animation.stand_START,y=animation.stand_END},anim_speed,0)
self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2 self.anim = ANIM_STAND
if ppos.x > pos.x then end
self.yaw = self.yaw+math.pi
end random_turn(self)
self.yaw = self.yaw-2
self.object:set_yaw(self.yaw) if velocity.x ~= 0
self.direction = {x=math.sin(self.yaw)*-1, y=0, z=math.cos(self.yaw)} or velocity.z ~= 0 then
self.object:setvelocity({x=0,y=velocity.y,z=0})
local direction = self.direction end
local dir_x = direction.x*2.5 end
local dir_y = velocity.y
local dir_z = direction.z*2.5 if self.state == 'walk' then
if self.anim ~= ANIM_WALK then
if not isnan(dir_x) and not isnan(dir_y) and not isnan(dir_z) then self.object:set_animation({x=animation.walk_START,y=animation.walk_END},anim_speed,0)
self.object:set_velocity({x=direction.x*2.5, y=velocity.y, z=direction.z*2.5}) self.anim = ANIM_WALK
else end
sneeker.log("warning", "Found NaN")
for k, v in ipairs({x=dir_x, y=dir_y, z=dir_z}) do self.direction = {x=math.sin(yaw)*-1,y=-10,z=math.cos(yaw)}
if isnan(v) then if self.direction then
sneeker.log("warning", "\"" .. k .. "\" is not a number: " .. tostring(v)) self.object:setvelocity({x=self.direction.x*walk_speed,y=velocity.y,z=self.direction.z*walk_speed})
end end
end
end random_turn(self)
end
end local velocity = self.object:getvelocity()
end
end if self.turn_timer > 1 then
local direction = self.direction
--[[ local npos = {x=pos.x+direction.x,y=pos.y+0.2,z=pos.z+direction.z}
if self.knockback then if velocity.x == 0 or velocity.z == 0
return or core.registered_nodes[core.get_node(npos).name].walkable then
end local select_turn = math.random(1,2)
if select_turn == 1 then
local ANIM_STAND = 1 self.turn = 'left'
local ANIM_WALK = 2 elseif select_turn == 2 then
self.turn = 'right'
local pos = self.object:get_pos() end
local yaw = self.object:get_yaw() self.turn_timer = 0
local inside = core.get_objects_inside_radius(pos, 10) self.turn_speed = 0.05*math.random()
local walk_speed = self.walk_speed end
local animation = self.animation end
local anim_speed = self.animation_speed
local velocity = self.object:get_velocity() -- Jump
if self.jump_timer > 0.2 then
self.timer = self.timer+0.01 jump(self,pos,self.direction)
self.turn_timer = self.turn_timer+0.01 end
self.jump_timer = self.jump_timer+0.01 end
if not self.chase if self.state == 'chase' then
and self.timer > math.random(2, 5) then if self.anim ~= ANIM_WALK then
if math.random() > 0.8 then self.object:set_animation({x=animation.walk_START,y=animation.walk_END},anim_speed,0)
self.state = "stand" self.anim = ANIM_WALK
else end
self.state = "walk"
end self.turn = 'straight'
self.timer = 0
end local inside_2 = core.get_objects_inside_radius(pos,2)
if self.turn == "right" then -- Boom
self.yaw = self.yaw+self.turn_speed if #inside_2 ~= 0 then
self.object:set_yaw(self.yaw) for _,object in ipairs(inside_2) do
elseif self.turn == "left" then if object:is_player() and object:get_hp() ~= 0 then
self.yaw = self.yaw-self.turn_speed self.chase = true
self.object:set_yaw(self.yaw) if self.visualx >= 2 then
end self.object:remove()
sneeker.boom(pos,self.powered)
if self.chase and self.visualx < 2 then core.sound_play('sneeker_explode',{pos=pos,gain=1.5,max_hear_distance=2*64})
if self.hiss == false then end
core.sound_play("sneeker_hiss", {pos=pos, gain=1.5, max_hear_distance=2*64}) end
end end
self.visualx = self.visualx+0.05 end
self.object:set_properties({
visual_size = {x=self.visualx, y=1} if #inside ~= 0 then
}) for _,object in ipairs(inside) do
self.hiss = true if object:is_player() and object:get_hp() ~= 0 then
elseif self.visualx > 1 then if #inside_2 ~= 0 then
self.visualx = self.visualx-0.05 for _,object in ipairs(inside_2) do
self.object:set_properties({ -- Stop move
visual_size = {x=self.visualx, y=1} if object:is_player() then
}) if self.anim ~= ANIM_STAND then
self.hiss = false self.object:set_animation({x=animation.stand_START,y=animation.stand_END},anim_speed,0)
end self.anim = ANIM_STAND
end
self.chase = false self.object:setvelocity({x=0,y=velocity.y,z=0})
return
for _, object in ipairs(inside) do end
if object:is_player() then end
self.state = "chase" end
end
end local ppos = object:getpos()
self.vec = {x=ppos.x-pos.x,y=ppos.y-pos.y,z=ppos.z-pos.z}
if self.state == "stand" then self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2
if self.anim ~= ANIM_STAND then if ppos.x > pos.x then
self.object:set_animation({x=animation.stand_START, y=animation.stand_END}, anim_speed, 0) self.yaw = self.yaw+math.pi
self.anim = ANIM_STAND end
end self.yaw = self.yaw-2
self.object:setyaw(self.yaw)
random_turn(self) self.direction = {x=math.sin(self.yaw)*-1,y=0,z=math.cos(self.yaw)}
if velocity.x ~= 0 local direction = self.direction
or velocity.z ~= 0 then self.object:setvelocity({x=direction.x*2.5,y=velocity.y,z=direction.z*2.5})
self.object:set_velocity({x=0, y=velocity.y, z=0})
end -- Jump
end if self.jump_timer > 0.2 then
jump(self,pos,direction)
if self.state == "walk" then end
if self.anim ~= ANIM_WALK then end
self.object:set_animation({x=animation.walk_START, y=animation.walk_END}, anim_speed, 0) end
self.anim = ANIM_WALK else
end self.state = 'stand'
end
self.direction = {x=math.sin(yaw)*-1, y=-10, z=math.cos(yaw)} end
if self.direction then
self.object:set_velocity({x=self.direction.x*walk_speed, y=velocity.y, z=self.direction.z*walk_speed}) -- Swim
end local node = core.get_node(pos)
if core.get_item_group(node.name,'water') ~= 0 then
random_turn(self) self.object:setacceleration({x=0,y=1,z=0})
local velocity = self.object:getvelocity()
local velocity = self.object:get_velocity() if self.object:getvelocity().y > 5 then
self.object:setvelocity({x=0,y=velocity.y-velocity.y/2,z=0})
if self.turn_timer > 1 then else
local direction = self.direction self.object:setvelocity({x=0,y=velocity.y+1,z=0})
local npos = {x=pos.x+direction.x, y=pos.y+0.2, z=pos.z+direction.z} end
if velocity.x == 0 or velocity.z == 0 else
or core.registered_nodes[core.get_node(npos).name].walkable then self.object:setacceleration({x=0,y=-10,z=0})
local select_turn = math.random(1, 2) end
if select_turn == 1 then end
self.turn = "left"
elseif select_turn == 2 then
self.turn = "right" def.on_punch = function(self,puncher,time_from_last_punch,tool_capabilities,dir)
end if self.knockback == false then
self.turn_timer = 0 local knockback_level = self.knockback_level
self.turn_speed = 0.05*math.random() self.object:setvelocity({x=dir.x*knockback_level,y=3,z=dir.z*knockback_level})
end self.knockback = true
end core.after(0.6,function()
self.knockback = false
-- Jump end)
if self.jump_timer > 0.2 then end
jump(self, pos, self.direction) if self.object:get_hp() < 1 then
end local pos = self.object:getpos()
end local x = 1/math.random(1,5)*dir.x
local z = 1/math.random(1,5)*dir.z
if self.state == "chase" then local p = {x=pos.x+x,y=pos.y,z=pos.z+z}
if self.anim ~= ANIM_WALK then local node = core.get_node_or_nil(p)
self.object:set_animation({x=animation.walk_START, y=animation.walk_END}, anim_speed, 0) if node == nil or not node.name or node.name ~= 'air' then
self.anim = ANIM_WALK p = pos
end end
local obj = core.add_item(p, {name='tnt:gunpowder',count=math.random(0,2)})
self.turn = "straight" end
end
local inside_2 = core.get_objects_inside_radius(pos, 2)
-- Boom def.get_staticdata = function(self)
if #inside_2 ~= 0 then return core.serialize({
for _, object in ipairs(inside_2) do powered = self.powered
if object:is_player() and object:get_hp() ~= 0 then })
self.chase = true end
if self.visualx >= 2 then
self.object:remove()
sneeker.boom(pos, self.powered) core.register_entity(sneeker.mob_name, def)
core.sound_play("sneeker_explode", {pos=pos, gain=1.5, max_hear_distance=2*64}) end
end
end
end
end
if #inside ~= 0 then
for _, object in ipairs(inside) do
if object:is_player() and object:get_hp() ~= 0 then
if #inside_2 ~= 0 then
for _, object in ipairs(inside_2) do
-- Stop move
if object:is_player() then
if self.anim ~= ANIM_STAND then
self.object:set_animation({x=animation.stand_START, y=animation.stand_END}, anim_speed, 0)
self.anim = ANIM_STAND
end
self.object:set_velocity({x=0, y=velocity.y, z=0})
return
end
end
end
local ppos = object:get_pos()
self.vec = {x=ppos.x-pos.x, y=ppos.y-pos.y, z=ppos.z-pos.z}
self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2
if ppos.x > pos.x then
self.yaw = self.yaw+math.pi
end
self.yaw = self.yaw-2
self.object:set_yaw(self.yaw)
self.direction = {x=math.sin(self.yaw)*-1, y=0, z=math.cos(self.yaw)}
local direction = self.direction
self.object:set_velocity({x=direction.x*2.5, y=velocity.y, z=direction.z*2.5})
-- Jump
if self.jump_timer > 0.2 then
jump(self, pos, direction)
end
end
end
else
self.state = "stand"
end
end
-- Swim
local node = core.get_node(pos)
if core.get_item_group(node.name, "water") ~= 0 then
self.object:set_acceleration({x=0, y=1, z=0})
local velocity = self.object:get_velocity()
if self.object:get_velocity().y > 5 then
self.object:set_velocity({x=0, y=velocity.y-velocity.y/2, z=0})
else
self.object:set_velocity({x=0, y=velocity.y+1, z=0})
end
else
self.object:set_acceleration({x=0, y=-10, z=0})
end
]]
end
--[[
def.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
if self.knockback == false then
local knockback_level = self.knockback_level
self.object:set_velocity({x=dir.x*knockback_level, y=3, z=dir.z*knockback_level})
self.knockback = true
core.after(0.6, function()
self.knockback = false
end)
end
if self.object:get_hp() < 1 then
local pos = self.object:get_pos()
local x = 1/math.random(1, 5)*dir.x
local z = 1/math.random(1, 5)*dir.z
local p = {x=pos.x+x, y=pos.y, z=pos.z+z}
local node = core.get_node_or_nil(p)
if node == nil or not node.name or node.name ~= "air" then
p = pos
end
local obj = core.add_item(p, {name="tnt:gunpowder", count=math.random(0, 2)})
end
end
]]
local sneeker_get_staticdata = function(self)
return core.serialize({
powered = self.powered
})
end
--core.register_entity(sneeker.mob_name, def)
local spawn_nodes = {
"default:dirt",
"default:dirt_with_grass",
"default:dry_dirt_with_dry_grass",
"default:desert_sand",
"default:sand",
"default:stone",
"default:desert_stone",
}
if core.global_exists("nether") then
table.insert(spawn_nodes, "nether:rack")
end
local drops = nil
if core.global_exists("tnt") then
drops = {
{"tnt:gunpowder", {min=1, max=2}, chance=0.66},
}
end
cmer.register_mob({
name = sneeker.mob_name,
stats = {
hp = 20,
lifetime = 15 * 60, -- 15 minutes
can_jump = 5,
has_kockback = true,
sneaky = true,
},
modes = {
idle = {chance=0.3, moving_speed=0,},
walk = {chance=0.7, moving_speed=1.5,},
follow = {chance=0.0, moving_speed=1.5,},
inflate = {chance=0.0, moving_speed=0,},
},
model = {
mesh = "character.b3d",
textures = {"sneeker.png"},
collisionbox = {-0.25, -0.7, -0.25, 0.25, 0.8, 0.25},
rotation = 270.0,
animations = {
idle = {start=0, stop=79, speed=30,},
walk = {start=168, stop=187, speed=30,},
follow = {start=168, stop=187, speed=30,},
inflate = {start=0, stop=79, speed=30,},
},
},
sounds = {},
drops = drops,
spawning = {
abm_nodes = {
spawn_on = spawn_nodes,
},
abm_interval = sneeker.spawn_interval,
abm_chance = sneeker.spawn_chance,
max_number = 1,
number = 1,
time_range = {min=0, max=23999},
light = {min=sneeker.spawn_minlight, max=sneeker.spawn_maxlight},
height_limit = {min=sneeker.spawn_minheight, max=sneeker.spawn_maxheight},
},
on_step = sneeker_on_step,
on_activate = sneeker_on_activate,
get_staticdata = sneeker_get_staticdata,
})
if core.global_exists("asm") then
asm.addEgg({
name = "sneeker",
inventory_image = "sneeker_spawnegg.png",
spawn = "sneeker:sneeker",
})
core.register_alias(old_spawnegg_name, "spawneggs:sneeker")
if core.registered_items["tnt:tnt"] then
asm.addEggRecipe("sneeker", "tnt:tnt")
end
end

View File

@@ -1,6 +1 @@
name = sneeker name = sneeker
title = Sneeker
description = An explosive nuisance.
author = Rui
depends = cmer, default, tnt
optional_depends = asm_spawneggs, nether

View File

@@ -1,53 +1,4 @@
-- Settings for sneeker mod -- Settings for sneeker mod
sneeker.time_min = 60 sneeker.debug = core.settings:get_bool('enable_debug_mods') or false
sneeker.debug = core.settings:get_bool("enable_debug_mods", false)
--- Sets maximum number of spawns that can exist in world at one time.
--
-- @setting sneeker.spawn_cap
sneeker.spawn_cap = tonumber(core.settings:get("sneeker.spawn_cap")) or 10
--- Sets possibility for spawn.
--
-- Inverted value (e.g. 10000 = 1/10000).
--
-- @setting sneeker.spawn_chance
sneeker.spawn_chance = tonumber(core.settings:get("sneeker.spawn_chance")) or 10000
--- Sets frequency of spawn chance.
--
-- Default 240 is equivalent to 4 minutes (60 * 4).
--
-- @setting sneeker.spawn_interval
sneeker.spawn_interval = tonumber(core.settings:get("sneeker.spawn_interval")) or sneeker.time_min * 4
--- Sets the minimum light that a node must have for spawn to occur.
--
-- Default: 0
--
-- @setting sneeker.spawn_minlight
sneeker.spawn_minlight = tonumber(core.settings:get("sneeker.spawn_minlight")) or 0
--- Sets the maximum light that a node can have for spawn to occur.
--
-- Default: 9
--
-- @setting sneeker.spawn_maxlight
sneeker.spawn_maxlight = tonumber(core.settings:get("sneeker.spawn_maxlight")) or 9
--- Sets the lowest position at which sneeker can spawn.
--
-- Default: -31000
--
-- @setting sneeker.spawn_minheight
sneeker.spawn_minheight = tonumber(core.settings:get("sneeker.spawn_minheight")) or -31000
--- Sets the highest position at which sneeker can spawn.
--
-- Default: 31000
--
-- @setting sneeker.spawn_maxheight
sneeker.spawn_maxheight = tonumber(core.settings:get("sneeker.spawn_maxheight")) or 31000

View File

@@ -1,23 +1,11 @@
# Sets maximum number of spawns that can exist in world. # Sets maximum number of spawns that can exist in world.
sneeker.spawn_cap (Sneeker maximum spawns) int 10 sneeker.spawn_cap (Maximum spawns) int 10
# Sets possibility for spawn. # Sets possibility for spawn.
sneeker.spawn_chance (Sneeker spawn chance) int 10000 sneeker.spawn_chance (Spawn chance) int 1000
# Sets frequency of spawn chance. Default 240 is equivalent to 4 minutes (60 * 4). # Sets frequency of spawn chance. Default 240 is equivalent to 4 minutes (60 * 4).
sneeker.spawn_interval (Sneeker spawn interval) int 240 sneeker.spawn_interval (Spawn interval) int 240
# Sets the minimum light that a node must have for spawn to occur.
sneeker.spawn_minlight (Sneeker min light for spawn) int 0
# Sets the maximum light that a node can have for spawn to occur. # Sets the maximum light that a node can have for spawn to occur.
sneeker.spawn_maxlight (Sneeker max light for spawn) int 9 sneeker.spawn_maxlight (Max light for spawn) int 5
# Sets the lowest position at which sneeker can spawn.
sneeker.spawn_minheight (Sneeker min spawn height) int -31000
# Sets the highest position at which sneeker can spawn.
sneeker.spawn_maxheight (Sneeker max spawn height) int 31000
# Logs extra debug messages.
enable_debug_mods (Enable debugging messages) bool false

183
spawn.lua
View File

@@ -1,84 +1,123 @@
-- Original code by Rui: WTFPL
local time_hr = sneeker.time_min * 60
local time_min = 60
local time_hr = time_min * 60
local time_day = time_hr * 24 local time_day = time_hr * 24
local spawn_cap = tonumber(core.settings:get('sneeker.spawn_cap')) or 10 -- Maximum number of spawns active at one time
local spawn_chance = tonumber(core.settings:get('sneeker.spawn_chance')) or 1000 -- 1/1000 chance of spawn
local spawn_interval = tonumber(core.settings:get('sneeker.spawn_interval')) or time_min * 4 -- Default interval is 4 minutes
local spawn_maxlight = tonumber(core.settings:get('sneeker.spawn_maxlight')) or 5 -- Maximum light of node for spawn
-- Display spawn chance as percentage in log -- Display spawn chance as percentage in log
local spawn_chance_percent = math.floor(1 / sneeker.spawn_chance * 100) local spawn_chance_percent = math.floor(1 / spawn_chance * 100)
if spawn_chance_percent < 1 then if spawn_chance_percent < 1 then
spawn_chance_percent = "Less than 1%" spawn_chance_percent = 'Less than 1%'
else else
spawn_chance_percent = tostring(spawn_chance_percent) .. "%" spawn_chance_percent = tostring(spawn_chance_percent) .. '%'
end end
sneeker.log("Spawn cap: " .. tostring(sneeker.spawn_cap)) sneeker.log('Spawn cap: ' .. tostring(spawn_cap))
sneeker.log("Spawn chance: " .. spawn_chance_percent) sneeker.log('Spawn chance: ' .. spawn_chance_percent)
sneeker.log("Spawn interval: " .. tostring(sneeker.spawn_interval) .. " (" .. tostring(sneeker.spawn_interval/60) .. " minute(s))") sneeker.log('Spawn interval: ' .. tostring(spawn_interval) .. ' (' .. tostring(spawn_interval/60) .. ' minute(s))')
sneeker.log("Maximum light value for spawn: " .. tostring(sneeker.spawn_maxlight)) sneeker.log('Maximum light value for spawn: ' .. tostring(spawn_maxlight))
local spawn_nodes = {"default:dirt_with_grass", "default:stone"}
if core.global_exists("nether") then
table.insert(spawn_nodes, "nether:rack")
end
core.register_abm({ if core.global_exists('mobs') then
nodenames = spawn_nodes, mobs:spawn({
neighbors = {"air"}, name = sneeker.mob_name,
interval = spawn_interval, nodes = {'default:dirt_with_grass', 'default:stone'},
chance = spawn_chance, neighbors = {'air'},
action = function(pos, node, _, active_object_count_wider) min_light = -1,
if active_object_count_wider > 5 then max_light = spawn_maxlight,
return interval = spawn_interval,
chance = spawn_chance,
})
mobs:register_egg(sneeker.mob_name, 'Sneeker Spawn Egg', 'sneeker_spawnegg.png', 0, false)
else
core.register_abm({
nodenames = {'default:dirt_with_grass', 'default:stone'},
neighbors = {'air'},
interval = spawn_interval,
chance = spawn_chance,
action = function(pos, node, _, active_object_count_wider)
if active_object_count_wider > 5 then
return
end
-- Check light value of node
pos.y = pos.y+1
local node_light = core.get_node_light(pos)
-- Debugging spawning
sneeker.log_debug('Node light level at ' .. sneeker.get_pos_string(pos) .. ': ' .. tostring(node_light))
if not node_light or node_light > spawn_maxlight or node_light < -1 then
sneeker.log_debug('Node not dark enough for spawn')
return
end
-- Spawn range
if pos.y > 31000 then
return
end
-- Node must be touching air
if core.get_node(pos).name ~= 'air' then
return
end
pos.y = pos.y+1
if core.get_node(pos).name ~= 'air' then
return
end
-- Get total count of sneekers in world
local count = 0
for I in pairs(core.luaentities) do
if core.luaentities[I].name == sneeker.mob_name then
count = count + 1
end
end
sneeker.log_debug('Current active spawns: ' .. tostring(count) .. '/' .. tostring(spawn_cap))
if count >= spawn_cap then
sneeker.log_debug('Max spawns reached')
return
end
sneeker.spawn(pos)
end end
})
-- Check light value of node
pos.y = pos.y+1
local node_light = core.get_node_light(pos) if core.get_modpath('spawneggs') and core.get_modpath('tnt') then
core.register_craftitem(sneeker.spawnegg_name, {
-- Debugging spawning description = 'Sneeker Spawn Egg',
sneeker.log("debug", "Node light level at " .. sneeker.get_pos_string(pos) .. ": " .. tostring(node_light)) inventory_image = 'sneeker_spawnegg.png',
on_place = function(itemstack, placer, pointed_thing)
-- Node light level if pointed_thing.type == 'node' then
if not node_light or node_light > spawn_maxlight then local pos = pointed_thing.above
sneeker.log("debug", "Node not dark enough for spawn") pos.y = pos.y+1
return core.add_entity(pos, sneeker.mob_name)
elseif node_light < spawn_minlight then if not core.settings:get_bool('creative_mode') then
sneeker.log("debug", "Node too dark for spawn") itemstack:take_item()
return end
end return itemstack
end
-- Spawn range end
if spawn_minheight ~= nil and pos.y < spawn_minheight then })
sneeker.log("debug", "Position is too low for spawn")
return core.register_craft({
elseif pos.y > spawn_maxheight then output = sneeker.spawnegg_name,
sneeker.log("debug", "Position is too high for spawn") type = 'shapeless',
return recipe = {
end 'spawneggs:egg', 'tnt:tnt',
},
-- Node must be touching air })
if core.get_node(pos).name ~= "air" then
return core.register_alias('spawneggs:sneeker', sneeker.spawnegg_name)
end
pos.y = pos.y+1
if core.get_node(pos).name ~= "air" then
return
end
-- Get total count of sneekers in world
local count = 0
for I in pairs(core.luaentities) do
if core.luaentities[I].name == sneeker.mob_name then
count = count + 1
end
end
sneeker.log("debug", "Current active spawns: " .. tostring(count) .. "/" .. tostring(spawn_cap))
if count >= spawn_cap then
sneeker.log("debug", "Max spawns reached")
return
end
sneeker.spawn(pos)
end end
}) end

View File

@@ -1,11 +1,13 @@
-- Original code by Rui: WTFPL
-- From TNT -- From TNT
local cid_data = {} local cid_data = {}
local radius = tonumber(core.settings:get("tnt_radius") or 3) local radius = tonumber(core.settings:get('tnt_radius') or 3)
local large_radius = 5 local large_radius = 5
local loss_prob = { local loss_prob = {
["default:cobble"] = 3, ['default:cobble'] = 3,
["default:dirt"] = 4, ['default:dirt'] = 4,
} }
core.after(0, function() core.after(0, function()
for name, def in pairs(core.registered_nodes) do for name, def in pairs(core.registered_nodes) do
@@ -38,8 +40,8 @@ local function eject_drops(drops, pos, radius)
local obj = core.add_item(drop_pos, item) local obj = core.add_item(drop_pos, item)
if obj then if obj then
obj:get_luaentity().collect = true obj:get_luaentity().collect = true
obj:set_acceleration({x=0, y=-10, z=0}) obj:setacceleration({x=0, y=-10, z=0})
obj:set_velocity({x=math.random(-3, 3), y=10, obj:setvelocity({x=math.random(-3, 3), y=10,
z=math.random(-3, 3)}) z=math.random(-3, 3)})
end end
count = count - max count = count - max
@@ -63,7 +65,7 @@ local function add_drop(drops, item)
end end
local function destroy(drops, pos, cid) local function destroy(drops, pos, cid)
if core.is_protected(pos, "") then if core.is_protected(pos, '') then
return return
end end
local def = cid_data[cid] local def = cid_data[cid]
@@ -73,7 +75,7 @@ local function destroy(drops, pos, cid)
end end
core.remove_node(pos) core.remove_node(pos)
if def then if def then
local node_drops = core.get_node_drops(def.name, "") local node_drops = core.get_node_drops(def.name, '')
for _, item in ipairs(node_drops) do for _, item in ipairs(node_drops) do
add_drop(drops, item) add_drop(drops, item)
end end
@@ -101,12 +103,12 @@ local function entity_physics(pos, radius)
radius = radius * 2 radius = radius * 2
local objs = core.get_objects_inside_radius(pos, radius) local objs = core.get_objects_inside_radius(pos, radius)
for _, obj in pairs(objs) do for _, obj in pairs(objs) do
local obj_pos = obj:get_pos() local obj_pos = obj:getpos()
local obj_vel = obj:get_velocity() local obj_vel = obj:getvelocity()
local dist = math.max(1, vector.distance(pos, obj_pos)) local dist = math.max(1, vector.distance(pos, obj_pos))
if obj_vel ~= nil then if obj_vel ~= nil then
obj:set_velocity(calc_velocity(pos, obj_pos, obj:setvelocity(calc_velocity(pos, obj_pos,
obj_vel, radius * 10)) obj_vel, radius * 10))
end end
@@ -129,7 +131,7 @@ local function add_effects(pos, radius)
maxexptime = 3, maxexptime = 3,
minsize = 8, minsize = 8,
maxsize = 16, maxsize = 16,
texture = "sneeker_smoke.png", texture = 'sneeker_smoke.png',
}) })
end end
@@ -147,16 +149,12 @@ local function explode(pos, radius)
local drops = {} local drops = {}
local p = {} local p = {}
local c_air = core.get_content_id("air") local c_air = core.get_content_id('air')
local c_tnt = nil local c_tnt = core.get_content_id('tnt:tnt')
if core.settings:get_bool("enable_tnt", false) then local c_tnt_burning = core.get_content_id('tnt:tnt_burning')
c_tnt = core.get_content_id("tnt:tnt") local c_gunpowder = core.get_content_id('tnt:gunpowder')
end local c_gunpowder_burning = core.get_content_id('tnt:gunpowder_burning')
local c_boom = core.get_content_id('tnt:boom')
local c_tnt_burning = core.get_content_id("tnt:tnt_burning")
local c_gunpowder = core.get_content_id("tnt:gunpowder")
local c_gunpowder_burning = core.get_content_id("tnt:gunpowder_burning")
local c_boom = core.get_content_id("tnt:boom")
for z = -radius, radius do for z = -radius, radius do
for y = -radius, radius do for y = -radius, radius do
@@ -185,13 +183,13 @@ local function explode(pos, radius)
return drops return drops
end end
function sneeker.boom(pos, large) function sneeker.boom(pos,large)
local radius = radius local radius = radius
if large then if large then
radius = large_radius radius = large_radius
end end
core.sound_play("sneeker_explode", {pos=pos, gain=1.5, max_hear_distance=2*64}) core.sound_play('sneeker_explode', {pos=pos, gain=1.5, max_hear_distance=2*64})
core.set_node(pos, {name="tnt:boom"}) core.set_node(pos, {name='tnt:boom'})
core.get_node_timer(pos):start(0.5) core.get_node_timer(pos):start(0.5)
local drops = explode(pos, radius) local drops = explode(pos, radius)
entity_physics(pos, radius) entity_physics(pos, radius)