2016-09-09 10:22:05 -07:00
-- boneworld by rnd, 2016
-- for more interesting bone gameplay:
-- you no longer get extra bones if you pick bones from player with same ip address (no suicide bone farming)
-- each player has experience points (xp)
-- when you die you loose 20% of your xp, half of that is stored in bones
2016-09-16 06:11:01 -07:00
-- (when you kill other player you get 10% of his xp)
2016-09-09 10:22:05 -07:00
-- if you pick up bones you get xp stored in bones
2016-09-16 06:11:01 -07:00
-- if you pick up other player bones you get 20% of average of your and bone owner xp award in extra bones (for example if you have 10 xp and you pick noob bone will get 2 bones instead of normally 1)
2016-09-09 10:22:05 -07:00
2017-01-05 04:46:40 -08:00
dofile ( minetest.get_modpath ( " boneworld " ) .. " /acid.lua " ) -- acid surprise when mining :)
dofile ( minetest.get_modpath ( " boneworld " ) .. " /gloves.lua " ) -- acid surprise when mining :)
local version = " 12/18/16 "
2016-09-09 10:22:05 -07:00
local worldpath = minetest.get_worldpath ( ) ;
2017-01-05 04:46:40 -08:00
2016-10-22 02:04:28 -07:00
--os.execute( "mkdir "..worldpath.. "\\boneworld")
minetest.mkdir ( worldpath .. " \\ boneworld " ) -- directory used to save xp data
2016-10-04 06:08:01 -07:00
boneworld = { } ;
2016-10-29 04:06:17 -07:00
boneworld.xp = { } ; -- [name] = bonexp, bone collect xp
boneworld.digxp = { } ; -- [name] = xp, mining xp
2017-01-05 04:46:40 -08:00
boneworld.thiefxp = { } ;
boneworld.killxp = { } ;
boneworld.bounty = { } ; --[name]=1
2016-10-29 04:06:17 -07:00
boneworld.protect = { } ; -- [name] = {timer, position}: time of last dig in unprotected area, position
2016-10-04 06:08:01 -07:00
2016-10-04 08:31:17 -07:00
-- those players get special dig xp when they join
2016-10-05 15:10:04 -07:00
boneworld.vipdig = { [ " abba " ] = 1000000 }
2016-10-04 06:08:01 -07:00
2016-09-15 09:37:43 -07:00
--boneworld.killxp = {}; -- xp obtained through kills
2016-09-09 10:22:05 -07:00
2016-09-10 06:02:38 -07:00
boneworld.wastedxp = 0 ; -- xp thats stored in bones and not yet reclaimed
2016-09-09 10:22:05 -07:00
2016-09-09 10:37:33 -07:00
local share_bones_time = tonumber ( minetest.setting_get ( " share_bones_time " ) ) or 1200
--local share_bones_time = tonumber(minetest.setting_get("share_bones_time")) or 20;
2016-09-09 10:22:05 -07:00
local share_bones_time_early = tonumber ( minetest.setting_get ( " share_bones_time_early " ) ) or share_bones_time / 4
local function is_owner ( pos , name )
local owner = minetest.get_meta ( pos ) : get_string ( " owner " )
if owner == " " or owner == name or minetest.check_player_privs ( name , " protection_bypass " ) then
return true
end
return false
end
2016-10-04 06:08:01 -07:00
2016-09-09 10:22:05 -07:00
local on_timer = function ( pos , elapsed )
local meta = minetest.get_meta ( pos )
2016-09-16 06:11:01 -07:00
local time = meta : get_int ( " time " ) + elapsed ;
2016-09-09 10:22:05 -07:00
if time >= share_bones_time then
2016-10-06 07:14:35 -07:00
meta : set_string ( " infotext " , meta : get_string ( " owner " ) .. " 's old bones (died " .. meta : get_string ( " date " ) .. " ), bone xp " .. math.floor ( meta : get_float ( " xp " ) * 100 ) / 100 ) ;
2016-09-09 10:22:05 -07:00
meta : set_string ( " owner " , " " )
else
2016-10-04 06:08:01 -07:00
2016-09-09 10:22:05 -07:00
if meta : get_int ( " active " ) == 0 then -- store data in bones, 1x
meta : set_int ( " active " , 1 ) ;
local owner = meta : get_string ( " owner " ) ;
meta : set_string ( " date " , os.date ( " %x " ) ) ;
meta : set_string ( " owner_orig " , owner ) ;
meta : set_string ( " ip " , tostring ( minetest.get_player_ip ( owner ) ) ) ;
2016-09-17 15:02:30 -07:00
if not minetest.get_player_by_name ( owner ) then -- mob bones
2016-10-06 07:14:35 -07:00
boneworld.xp [ owner ] = 0.1 -- 0.1th of noob player xp in mobs bone
time = 0.9 * share_bones_time ; -- 10x shorter old bone time
2016-09-16 06:11:01 -07:00
else
boneworld.xp [ owner ] = boneworld.xp [ owner ] or 1 ;
2016-10-05 15:10:04 -07:00
time = 0 ;
2016-09-16 06:11:01 -07:00
end
2016-10-06 07:14:35 -07:00
if boneworld.xp [ owner ] < 1 then
meta : set_float ( " xp " , 0.01 ) -- mobs or bones with 0 xp
2016-09-16 06:11:01 -07:00
else
2016-10-06 07:14:35 -07:00
meta : set_float ( " xp " , 0.1 ) ; -- player bones give 0.1 xp, same as 10 mob bones
2016-09-16 06:11:01 -07:00
end
boneworld.wastedxp = boneworld.wastedxp + meta : get_float ( " xp " ) ;
2017-01-05 04:46:40 -08:00
if boneworld.bounty [ owner ] then
meta : set_string ( " owner " , " " ) ;
meta : set_string ( " infotext " , " Here lies the KILLER " .. owner .. " , bone xp " .. math.floor ( meta : get_float ( " xp " ) * 100 ) / 100 .. " . get his bones ! " ) ;
else
meta : set_string ( " infotext " , " Here lies " .. owner .. " , bone xp " .. math.floor ( meta : get_float ( " xp " ) * 100 ) / 100 ) ;
end
2016-09-09 10:22:05 -07:00
end
2016-10-04 06:08:01 -07:00
2016-09-09 10:22:05 -07:00
meta : set_int ( " time " , time )
return true
end
end
local on_punch = function ( pos , node , player )
if ( not is_owner ( pos , player : get_player_name ( ) ) ) then
return
end
if ( minetest.get_meta ( pos ) : get_string ( " infotext " ) == " " ) then
return
end
local inv = minetest.get_meta ( pos ) : get_inventory ( )
local player_inv = player : get_inventory ( )
local has_space = true
for i = 1 , inv : get_size ( " main " ) do
local stk = inv : get_stack ( " main " , i )
if player_inv : room_for_item ( " main " , stk ) then
inv : set_stack ( " main " , i , nil )
player_inv : add_item ( " main " , stk )
else
has_space = false
break
end
end
-- remove bones if player emptied them
if has_space then
local meta = minetest.get_meta ( pos ) ;
local active = meta : get_int ( " active " ) == 1 ;
local puncher = player : get_player_name ( ) ;
2016-10-06 07:14:35 -07:00
-- award extra bones/xp if you collect bones from different ip player
2016-09-09 10:22:05 -07:00
--debug
if active and meta : get_string ( " ip " ) ~= tostring ( minetest.get_player_ip ( puncher ) ) then
2016-09-30 13:40:34 -07:00
local xp = meta : get_float ( " xp " ) ; if xp == 0 then xp = 0.01 end
2016-09-09 10:22:05 -07:00
-- average of owners xp (at time of death) and puncher xp will be awarded as extra bones
2016-09-16 06:11:01 -07:00
-- with every 10 more xp one bone
2016-10-06 07:14:35 -07:00
local count ;
if boneworld.xp [ puncher ] > 100 then -- dont give more bones when bone xp exceeds 100
count = 1 + 0.1 * 100 ;
else
count = 1 + 0.1 * boneworld.xp [ puncher ] ;
end
2016-09-09 10:22:05 -07:00
count = math.floor ( count ) ;
2016-09-16 14:42:29 -07:00
minetest.chat_send_player ( puncher , " you find " .. count .. " bones in the corpse. " ) ;
2016-09-09 10:22:05 -07:00
if player_inv : room_for_item ( " main " , ItemStack ( " bones:bones " .. count ) ) then
player_inv : add_item ( " main " , ItemStack ( " bones:bones " .. count ) )
else
minetest.add_item ( pos , ItemStack ( " bones:bones " .. count ) )
end
2016-10-06 07:14:35 -07:00
-- add xp from bones to player who retrieved bones;
boneworld.xp [ puncher ] = boneworld.xp [ puncher ] + meta : get_float ( " xp " ) ;
boneworld.wastedxp = boneworld.wastedxp - meta : get_float ( " xp " ) ;
2016-09-09 10:22:05 -07:00
end
2017-01-05 04:46:40 -08:00
local owner_orig = meta : get_string ( " owner_orig " )
if boneworld.bounty [ owner_orig ] and owner_orig ~= " " and owner_orig ~= puncher then
boneworld.bounty [ owner_orig ] = false ;
minetest.chat_send_all ( " *** BOUNTY *** for killer " .. owner_orig .. " has been cleared ! " )
end
2016-09-10 06:02:38 -07:00
2016-09-09 10:22:05 -07:00
minetest.remove_node ( pos )
end
end
-- load xp
minetest.register_on_joinplayer (
function ( player )
local name = player : get_player_name ( ) ;
if not boneworld.xp [ name ] then -- load xp
local filename = worldpath .. " \\ boneworld \\ " .. name .. " .xp " ;
local f = io.open ( filename , " r " ) ;
if not f then -- file does not yet exist
boneworld.xp [ name ] = 1 ;
2016-10-04 06:08:01 -07:00
boneworld.digxp [ name ] = 0 ;
2017-01-05 04:46:40 -08:00
boneworld.thiefxp [ name ] = 0 ;
boneworld.killxp [ name ] = 0 ;
2016-10-04 08:31:17 -07:00
else
local str = f : read ( " *a " ) or 1 ;
local words = { } ;
for w in str : gmatch ( " %S+ " ) do
words [ # words + 1 ] = w
end
boneworld.xp [ name ] = tonumber ( words [ 1 ] or 1 ) ;
boneworld.digxp [ name ] = tonumber ( words [ 2 ] or 0 ) ;
2017-01-05 04:46:40 -08:00
boneworld.thiefxp [ name ] = tonumber ( words [ 3 ] or 0 ) ;
boneworld.killxp [ name ] = tonumber ( words [ 4 ] or 0 ) ;
2016-10-04 08:31:17 -07:00
f : close ( ) ;
2016-09-09 10:22:05 -07:00
end
2016-10-04 08:31:17 -07:00
end
if boneworld.vipdig [ name ] then
if boneworld.digxp [ name ] < boneworld.vipdig [ name ] then
boneworld.digxp [ name ] = boneworld.vipdig [ name ] ;
2016-10-04 06:08:01 -07:00
end
2016-09-09 10:22:05 -07:00
end
2016-10-04 08:31:17 -07:00
2016-09-09 10:22:05 -07:00
end
)
-- save xp
minetest.register_on_leaveplayer (
function ( player )
local name = player : get_player_name ( ) ;
2016-10-07 06:14:50 -07:00
local bonexp = boneworld.xp [ name ] or 1 ;
2016-10-04 06:08:01 -07:00
local digxp = boneworld.digxp [ name ] or 0 ;
2017-01-05 04:46:40 -08:00
local thiefxp = boneworld.thiefxp [ name ] or 0 ;
local killxp = boneworld.killxp [ name ] or 0 ;
2016-09-09 10:43:05 -07:00
--debug
2017-01-05 04:46:40 -08:00
if bonexp > 1.5 or digxp > 0.25 then -- save xp for serious players only
2016-09-09 10:22:05 -07:00
local filename = worldpath .. " \\ boneworld \\ " .. name .. " .xp " ;
local f = io.open ( filename , " w " ) ;
if not f then return end
2017-01-05 04:46:40 -08:00
f : write ( bonexp .. " " .. digxp .. " " .. thiefxp .. " " .. killxp ) ;
2016-09-09 10:22:05 -07:00
f : close ( ) ;
else
-- dont save, player didnt do anything
end
end
)
2017-01-05 04:46:40 -08:00
boneworld.save_xp = function ( player )
if not player then return end
local name = player : get_player_name ( ) ;
local bonexp = boneworld.xp [ name ] or 1 ;
local digxp = boneworld.digxp [ name ] or 0 ;
local thiefxp = boneworld.thiefxp [ name ] or 0 ;
--debug
if bonexp > 1.5 or digxp > 0.25 then -- save xp for serious players only
local filename = worldpath .. " \\ boneworld \\ " .. name .. " .xp " ;
local f = io.open ( filename , " w " ) ;
if not f then return end
f : write ( bonexp .. " " .. digxp .. " " .. thiefxp ) ;
f : close ( ) ;
else
-- dont save, player didnt do anything
end
end
boneworld.save_all_xp = function ( )
local players = minetest.get_connected_players ( ) ;
for _ , player in pairs ( players ) do
boneworld.save_xp ( player )
end
end
minetest.register_on_leaveplayer ( boneworld.save_xp )
minetest.register_on_shutdown ( boneworld.save_all_xp )
2016-10-06 07:14:35 -07:00
minetest.register_on_dieplayer ( -- -1 bone xp each time you die; otherwise no motivation to be careful
function ( player )
local name = player : get_player_name ( ) ;
local xp = boneworld.xp [ name ] or 1 ;
if xp > 2 then
xp = xp - 1
else
xp = 1 ;
end
boneworld.xp [ name ] = xp ;
end
)
2017-01-05 04:46:40 -08:00
minetest.register_on_punchplayer (
function ( player , hitter , time_from_last_punch , tool_capabilities , dir , damage )
local php = player : get_hp ( ) ;
--minetest.chat_send_all(" HIT " .. php .. " " .. damage)
if php > 0 and php - damage <= 0 then -- killed
local hname = hitter : get_player_name ( ) ;
local killxp = boneworld.killxp [ hname ] or 0 ;
boneworld.killxp [ hname ] = killxp + 0.01 ;
local pname = player : get_player_name ( ) ;
if boneworld.bounty [ pname ] and boneworld.bounty [ pname ] > 0 then
boneworld.bounty [ pname ] = - 1
minetest.chat_send_all ( " **** BOUNTY **** killer " .. pname .. " has been killed! You can now get his bones as a reward! " ) ;
local killxp = boneworld.killxp [ pname ] or 0 ;
killxp = killxp - 0.1 ; if killxp < 0 then killxp = 0 end
boneworld.killxp [ pname ] = killxp ;
end
end
end
)
2016-09-09 10:22:05 -07:00
local tweak_bones = function ( )
local name = " bones:bones " ;
local table = minetest.registered_nodes [ name ] ;
2016-10-07 06:14:50 -07:00
--table.on_construct = on_construct;
2016-09-09 10:22:05 -07:00
table.on_punch = on_punch ;
table.on_timer = on_timer ;
minetest.register_node ( " : " .. name , table ) ;
end
minetest.after ( 0 , tweak_bones ) ;
minetest.register_chatcommand ( " xp " , {
2017-01-05 04:46:40 -08:00
description = " xp name - show experience of target player " .. version ,
2016-09-09 10:22:05 -07:00
privs = {
interact = true
} ,
func = function ( name , param )
2016-09-10 06:02:38 -07:00
2016-10-04 06:08:01 -07:00
local msg ;
2016-09-09 10:22:05 -07:00
if param == " " then
2017-01-05 04:46:40 -08:00
local xp = math.floor ( ( boneworld.xp [ name ] or 1 ) * 100 ) / 100 ;
local digxp = math.floor ( ( boneworld.digxp [ name ] or 0 ) * 100 ) / 100 ;
local thiefxp = math.floor ( ( boneworld.thiefxp [ name ] or 0 ) * 100 ) / 100 ;
local killxp = math.floor ( ( boneworld.killxp [ name ] or 0 ) * 100 ) / 100 ;
2016-10-06 07:22:00 -07:00
msg = " xp name - show experience of target player "
2017-01-05 04:46:40 -08:00
.. " \n # " .. name .. " has " .. xp .. " bone collecting experience, " .. digxp .. " digging experience " ..
" (can dig to " .. math.floor ( 200 + 50 * math.sqrt ( digxp ) ) .. " ), " .. thiefxp .. " thief experience, " ..
killxp .. " kill experience " ..
" \n Total xp stored in bones in world is " .. math.floor ( boneworld.wastedxp * 100 ) / 100 ;
2016-09-09 10:22:05 -07:00
else
2016-09-10 06:02:38 -07:00
local xp = math.floor ( ( boneworld.xp [ param ] or 1 ) * 100 ) / 100 ;
2016-10-04 06:08:01 -07:00
local digxp = math.floor ( ( boneworld.digxp [ param ] or 0 ) * 100 ) / 100 ;
2017-01-05 04:46:40 -08:00
local thiefxp = math.floor ( ( boneworld.thiefxp [ param ] or 0 ) * 100 ) / 100 ;
local killxp = math.floor ( ( boneworld.killxp [ param ] or 0 ) * 100 ) / 100 ;
2016-10-04 06:08:01 -07:00
msg = " xp name - show experience of target player (10.04.16) "
2017-01-05 04:46:40 -08:00
.. " \n # " .. param .. " has " .. xp .. " bone collecting experience, " .. digxp .. " digging experience, " .. thiefxp .. " thief experience, " .. killxp .. " kill experience " ;
2016-10-04 06:08:01 -07:00
2016-09-09 10:22:05 -07:00
end
minetest.chat_send_player ( name , msg ) ;
end
2016-10-04 06:08:01 -07:00
} )
2016-09-30 13:40:34 -07:00
-- limit digging to above -(200+xp*5)
local old_is_protected = minetest.is_protected
function minetest . is_protected ( pos , name )
2016-10-29 04:06:17 -07:00
local is_protected_new = old_is_protected ( pos , name ) ;
2016-10-05 15:10:04 -07:00
if pos.y >- 200 or name == " " then
2016-10-04 06:08:01 -07:00
2016-10-29 04:06:17 -07:00
else
--to do : digxp here!!
local digxp = boneworld.digxp [ name ] or 0 ;
local maxdepth = 200 + 50 * math.sqrt ( digxp ) ;
if pos.y <- maxdepth then
minetest.chat_send_player ( name , " You can only dig above - " .. math.floor ( maxdepth ) .. " . Get more dig experience to dig deeper " ) ;
local player = minetest.get_player_by_name ( name ) ; if not player then return true end
2017-01-05 04:46:40 -08:00
if pos.y <- maxdepth - 5 then
player : setpos ( { x = 0 , y = 1 , z = 0 } )
minetest.chat_send_player ( name , " You tried to dig too deep. Get more dig experience to dig deeper " ) ;
end
2016-10-29 04:06:17 -07:00
is_protected_new = true
2017-01-05 04:46:40 -08:00
--local player = minetest.get_player_by_name(name); if not player then return true end
--local protect_data = boneworld.protect[name];
--local tpos;
-- if not protect_data then -- safety check
-- boneworld.protect[name] = {t=minetest.get_gametime(), pos=pos};
-- tpos = pos
-- else
-- tpos = boneworld.protect[name].pos;
-- end
-- player:setpos({x=tpos.x,y=tpos.y+1,z=tpos.z});
2016-10-29 04:06:17 -07:00
end
2016-09-30 13:40:34 -07:00
end
2016-10-29 04:06:17 -07:00
2017-01-05 04:46:40 -08:00
-- if not is_protected_new then -- remember time, pos of last dig in unprotected area
-- local t1 = minetest.get_gametime();
-- local t0;
-- local protect_data = boneworld.protect[name];
-- if not protect_data then
-- boneworld.protect[name] = {t=t1, pos=pos};
-- t0 = t1;
-- else
-- t0 = boneworld.protect[name].t;
-- end
-- if t1-t0>10 then -- "time" to remember new time, pos
-- boneworld.protect[name].t = t1;
-- boneworld.protect[name].pos = pos;
-- end
-- end
2016-10-29 04:06:17 -07:00
return is_protected_new ;
2016-09-30 13:40:34 -07:00
end
2016-10-04 06:08:01 -07:00
-- mining xp
-- how much mining xp digging minerals yields
boneworld.mineralxp = {
[ " default:stone " ] = 0.01 ,
[ " default:stone_with_coal " ] = 0.03 ,
[ " default:stone_with_iron " ] = 0.1 ,
[ " default:stone_with_copper " ] = 0.1 ,
[ " default:stone_with_gold " ] = 0.2 ,
[ " default:stone_with_mese " ] = 0.5 ,
[ " default:stone_with_diamond " ] = 1 ,
2017-01-05 04:46:40 -08:00
[ " moreores:mineral_silver " ] = 0.2 ,
[ " moreores:mineral_tin " ] = 0.1 ,
[ " moreores:mineral_mithril " ] = 2 ,
2016-10-04 06:08:01 -07:00
}
local after_dig_node = function ( pos , oldnode , oldmetadata , digger )
local nodename = oldnode.name ;
local name = digger : get_player_name ( ) ;
local digxp = boneworld.mineralxp [ nodename ] or 0 ; digxp = digxp * 0.1 ; -- bonus xp
2016-10-11 23:37:36 -07:00
local xp = boneworld.digxp [ name ] or 0 ;
xp = xp + digxp ;
2016-10-04 06:08:01 -07:00
boneworld.digxp [ name ] = xp ;
2017-01-05 04:46:40 -08:00
if digxp > 0 and pos.y <- 100 then -- only underground; acid surprise :)
if math.random ( 100 ) == 1 then
minetest.set_node ( pos , { name = " boneworld:acid_source_active " } )
end
end
2016-10-04 06:08:01 -07:00
-- extra reward with small probability
if xp < 100 or nodename == " default:stone " or digxp == 0 then return end
local P ;
if xp > 10000 then
P = 0.5
else
P = ( xp / 10000 + 0.0001 ) * 0.5 ;
end
2016-10-05 15:10:04 -07:00
if math.random ( 1 / P ) == 1 then
P = 1 ;
end
2016-10-04 06:08:01 -07:00
if P == 1 then
local player_inv = digger : get_inventory ( )
local stk = ItemStack ( nodename ) ;
if player_inv : room_for_item ( " main " , stk ) then
--minetest.chat_send_player(name, "Congratulations! You found extra " .. nodename)
player_inv : add_item ( " main " , stk )
end
end
2017-01-05 04:46:40 -08:00
2016-10-04 06:08:01 -07:00
end
local set_after_dig_node = function ( name )
local tabl = minetest.registered_nodes [ name ] ;
if not tabl then return end
minetest.override_item ( name , { after_dig_node = after_dig_node } )
end
minetest.after ( 0 ,
function ( )
set_after_dig_node ( " default:stone " ) ;
set_after_dig_node ( " default:stone_with_iron " ) ;
set_after_dig_node ( " default:stone_with_copper " ) ;
set_after_dig_node ( " default:stone_with_coal " ) ;
set_after_dig_node ( " default:stone_with_gold " ) ;
set_after_dig_node ( " default:stone_with_mese " ) ;
set_after_dig_node ( " default:stone_with_diamond " ) ;
end
2016-10-22 02:04:28 -07:00
)