diff --git a/builtin/game/statbars.lua b/builtin/game/statbars.lua index 0d2912eaf..ac618d6a0 100644 --- a/builtin/game/statbars.lua +++ b/builtin/game/statbars.lua @@ -174,7 +174,7 @@ local function add_text(player) hud[player_name] = player:hud_add({ hud_elem_type = "text", position = {x = 0.5, y = 0.975}, - offset = {x = 0, y = -75}, + offset = {x = 0, y = -100}, alignment = {x = 0, y = 0}, number = 0xFFFFFF, text = "", diff --git a/games/default/files/experience/depends.txt b/games/default/files/experience/depends.txt new file mode 100644 index 000000000..331d858ce --- /dev/null +++ b/games/default/files/experience/depends.txt @@ -0,0 +1 @@ +default \ No newline at end of file diff --git a/games/default/files/experience/init.lua b/games/default/files/experience/init.lua new file mode 100644 index 000000000..22fb10dc3 --- /dev/null +++ b/games/default/files/experience/init.lua @@ -0,0 +1,212 @@ +experience = {} + +local modname = minetest.get_current_modname() +local modpath = minetest.get_modpath(modname) + +dofile(modpath .. "/override.lua") + +local MAX_HUD_XP = 44 +local MAX_LEVEL = 40 +local ORB_SOUND_INTERVAL = 0.01 +local ORB_COLLECT_RADIUS = 3 + +local xp, hud = {}, {} + +local get_objs_rad = minetest.get_objects_inside_radius +local get_players = minetest.get_connected_players + +local vec_new, vec_dist, vec_mul, vec_sub = + vector.new, vector.distance, vector.multiply, vector.subtract + +local function init_data(player, reset) + local name = player:get_player_name() + local _xp = minetest.deserialize(player:get_attribute("xp")) + + if not _xp or reset then + xp[name] = { + xp_bar = 0, + xp_total = 0, + xp_number = 0, + level = 0, + } + else + xp[name] = _xp + end +end + +minetest.register_on_joinplayer(function(player) + local name = player:get_player_name() + init_data(player) + + hud[name] = { + -- background (empty bar) + hud = player:hud_add({ + hud_elem_type = "statbar", + position = {x = 0.5, y = 0.97}, + offset = {x = -252, y = -48}, + scale = {x = 1, y = 1}, + alignment = {x = -1, y = -1}, + text = "expbar_empty.png", + number = MAX_HUD_XP, + }), + + -- foreground (filling bar) + hud2 = player:hud_add({ + hud_elem_type = "statbar", + position = {x = 0.5, y = 0.97}, + offset = {x = -252, y = -48}, + scale = {x = 1, y = 1}, + alignment = {x = -1, y = -1}, + text = "expbar_full.png", + }), + + -- level number + hud3 = player:hud_add({ + hud_elem_type = "text", + texture = ("xp_blank"), + position = {x = 0.5, y = 0.97}, + offset = {x = 6, y = -42}, + alignment = {x = -1, y = -1}, + number = 0x3cff00, + text = "", + }) + } +end) + +function experience.add_orb(amount, pos) + if amount == 0 then return end + for _ = 1, amount do + local area = vec_new( + pos.x + math.random(0,5) / 5 - 0.5, + pos.y, + pos.z + math.random(0,5) / 5 - 0.5) + + minetest.add_entity(area, "experience:orb") + end +end + +function experience.get_level(name) + return xp[name].level +end + +minetest.register_on_dignode(function(pos, oldnode, digger) + local name = oldnode.name + local xp_min = minetest.get_item_group(name, "xp_min") + local xp_max = minetest.get_item_group(name, "xp_max") + + if xp_min and xp_max and xp_max > 0 then + experience.add_orb(math.random(xp_min, xp_max), pos) + end +end) + +minetest.register_on_newplayer(function(player) + init_data(player) +end) + +minetest.register_on_dieplayer(function(player) + init_data(player, true) +end) + +minetest.register_globalstep(function(dtime) + local players = get_players() + for i = 1, #players do + local player = players[i] + local name = player:get_player_name() + local pos = player:get_pos() + pos.y = pos.y + 0.5 + + xp[name].timer = (xp[name].timer or 0) + dtime + + for _, obj in ipairs(get_objs_rad(pos, ORB_COLLECT_RADIUS)) do + local ent = obj:get_luaentity() + if not obj:is_player() and ent and ent.name == "experience:orb" then + local orb_pos = obj:get_pos() + + if vec_dist(pos, orb_pos) <= 1 then + if xp[name].timer >= ((xp[name].last_sound or 0) + ORB_SOUND_INTERVAL) then + minetest.sound_play("orb", {to_player = name}) + xp[name].last_sound = xp[name].timer + end + + local inc = 2 * xp[name].level + 7 + + if xp[name].level >= 16 then + inc = 5 * xp[name].level - 38 + elseif xp[name].level >= 31 then + inc = 9 * xp[name].level - 158 + end + + xp[name].xp_bar = xp[name].xp_bar + (MAX_HUD_XP / inc) + obj:remove() + else + pos.y = pos.y + 0.2 + local vec = vec_mul(vec_sub(pos, orb_pos), 3) + obj:set_velocity(vec) + end + end + end + + if xp[name].xp_bar >= MAX_HUD_XP then + if xp[name].level < MAX_LEVEL then + xp[name].level = xp[name].level + 1 + xp[name].xp_bar = xp[name].xp_bar - MAX_HUD_XP + else + xp[name].xp_bar = MAX_HUD_XP + end + end + + player:hud_change(hud[name].hud2, "number", xp[name].xp_bar) + player:hud_change(hud[name].hud3, "text", xp[name].level) + + player:hud_change(hud[name].hud3, "offset", + {x = (xp[name].level >= 10 and 13 or 6), y = -42}) + end +end) + +minetest.register_entity("experience:orb", { + timer = 0, + glow = 12, + physical = true, + textures = {"orb.png"}, + visual_size = {x = 0.15, y = 0.15}, + collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1}, + collide_with_objects = false, + + on_activate = function(self, staticdata) + local obj = self.object + obj:set_armor_groups({immortal = 1}) + obj:set_velocity(vec_new(0, 1, 0)) + obj:set_acceleration(vec_new(0, -9.81, 0)) + end, + + on_step = function(self, dtime) + local obj = self.object + self.timer = self.timer + dtime + self.last_color_change = self.last_color_change or 0 + self.color_ratio = self.color_ratio or 0 + + if self.timer > 300 then + obj:remove() + elseif self.timer >= self.last_color_change + 0.001 then + if self.color_ratio >= 120 then + self.color_back = true + elseif self.color_ratio <= 0 then + self.color_back = nil + end + + self.color_ratio = self.color_ratio + (self.color_back and -10 or 10) + obj:set_texture_mod("^[colorize:#e5ff02:" .. self.color_ratio) + self.last_color_change = self.timer + end + end, +}) + +minetest.register_on_shutdown(function() + local players = get_players() + for i = 1, #players do + local player = players[i] + local name = player:get_player_name() + + player:set_attribute("xp", minetest.serialize(xp[name])) + end +end) diff --git a/games/default/files/experience/override.lua b/games/default/files/experience/override.lua new file mode 100644 index 000000000..d45b678ec --- /dev/null +++ b/games/default/files/experience/override.lua @@ -0,0 +1,7 @@ +minetest.override_item("default:stone_with_coal", { + groups = {cracky = 3, xp_min = 0, xp_max = 2}, +}) + +minetest.override_item("default:wood", { + groups = {dig_immediate = 3, xp_min = 4, xp_max = 6}, +}) diff --git a/games/default/files/experience/sounds/attributes.txt b/games/default/files/experience/sounds/attributes.txt new file mode 100644 index 000000000..e9fc44559 --- /dev/null +++ b/games/default/files/experience/sounds/attributes.txt @@ -0,0 +1 @@ +http://www.freesound.org/people/partymix/sounds/24102/ diff --git a/games/default/files/experience/sounds/level_up.ogg b/games/default/files/experience/sounds/level_up.ogg new file mode 100644 index 000000000..c6eeb6e44 Binary files /dev/null and b/games/default/files/experience/sounds/level_up.ogg differ diff --git a/games/default/files/experience/sounds/orb.1.ogg b/games/default/files/experience/sounds/orb.1.ogg new file mode 100644 index 000000000..48b32a1ae Binary files /dev/null and b/games/default/files/experience/sounds/orb.1.ogg differ diff --git a/games/default/files/experience/sounds/orb.2.ogg b/games/default/files/experience/sounds/orb.2.ogg new file mode 100644 index 000000000..6f6c2bd24 Binary files /dev/null and b/games/default/files/experience/sounds/orb.2.ogg differ diff --git a/games/default/files/experience/sounds/orb.3.ogg b/games/default/files/experience/sounds/orb.3.ogg new file mode 100644 index 000000000..3a9d69a27 Binary files /dev/null and b/games/default/files/experience/sounds/orb.3.ogg differ diff --git a/games/default/files/experience/sounds/orb.4.ogg b/games/default/files/experience/sounds/orb.4.ogg new file mode 100644 index 000000000..2a953a193 Binary files /dev/null and b/games/default/files/experience/sounds/orb.4.ogg differ diff --git a/games/default/files/experience/textures/expbar_empty.png b/games/default/files/experience/textures/expbar_empty.png new file mode 100644 index 000000000..c6876b543 Binary files /dev/null and b/games/default/files/experience/textures/expbar_empty.png differ diff --git a/games/default/files/experience/textures/expbar_full.png b/games/default/files/experience/textures/expbar_full.png new file mode 100644 index 000000000..45ca370cf Binary files /dev/null and b/games/default/files/experience/textures/expbar_full.png differ diff --git a/games/default/files/experience/textures/orb.png b/games/default/files/experience/textures/orb.png new file mode 100644 index 000000000..f4945a478 Binary files /dev/null and b/games/default/files/experience/textures/orb.png differ diff --git a/games/default/files/experience/textures/xp_empty.png b/games/default/files/experience/textures/xp_empty.png new file mode 100644 index 000000000..215e0d3e4 Binary files /dev/null and b/games/default/files/experience/textures/xp_empty.png differ diff --git a/games/default/files/hud/builtin.lua b/games/default/files/hud/builtin.lua index 76468afe9..e4034435b 100644 --- a/games/default/files/hud/builtin.lua +++ b/games/default/files/hud/builtin.lua @@ -1,12 +1,12 @@ -HUD_SB_SIZE = {x = 24, y = 24} -HUD_HEALTH_POS = {x = 0.5, y = 1} -HUD_HEALTH_OFFSET = {x = -248, y = -93} -HUD_AIR_POS = {x = 0.5, y = 1} -HUD_AIR_OFFSET = {x = 6, y = -124} -HUD_HUNGER_POS = {x = 0.5, y = 1} -HUD_HUNGER_OFFSET = {x = 6, y = -93} -HUD_ARMOR_POS = {x = 0.5, y = 1} -HUD_ARMOR_OFFSET = {x = -248, y = -124} +HUD_SB_SIZE = {x = 24, y = 24} +HUD_HEALTH_POS = {x = 0.5, y = 1} +HUD_HEALTH_OFFSET = {x = -248, y = -110} +HUD_AIR_POS = {x = 0.5, y = 1} +HUD_AIR_OFFSET = {x = 6, y = -124} +HUD_HUNGER_POS = {x = 0.5, y = 1} +HUD_HUNGER_OFFSET = {x = 6, y = -110} +HUD_ARMOR_POS = {x = 0.5, y = 1} +HUD_ARMOR_OFFSET = {x = -248, y = -124} -- read hud.conf settings function hud.read_conf() diff --git a/games/default/files/mobs_animal/pig.lua b/games/default/files/mobs_animal/pig.lua index 3ee2680ee..f7225819f 100644 --- a/games/default/files/mobs_animal/pig.lua +++ b/games/default/files/mobs_animal/pig.lua @@ -26,11 +26,18 @@ mobs:register_mob("mobs_animal:pig", { jump = true, follow = {"default:apple", "farming:potato"}, view_range = 5, - drops = { - {name = "mobs:pork_raw", chance = 1, min = 1, max = 1}, - {name = "mobs:pork_raw", chance = 2, min = 1, max = 1}, - {name = "mobs:pork_raw", chance = 2, min = 1, max = 1} - }, + drops = function(pos) + if rawget(_G, "experience") then + --experience.add_orb(math.random(1,3), pos) -- random amount between 1 and 3 + experience.add_orb(3, pos) + end + + return { + {name = "mobs:pork_raw", chance = 1, min = 1, max = 1}, + {name = "mobs:pork_raw", chance = 2, min = 1, max = 1}, + {name = "mobs:pork_raw", chance = 2, min = 1, max = 1} + } + end, water_damage = 0, lava_damage = 5, light_damage = 0, diff --git a/games/default/files/mobs_redo/api.lua b/games/default/files/mobs_redo/api.lua index 7dcdbc2a0..3a146e4c3 100644 --- a/games/default/files/mobs_redo/api.lua +++ b/games/default/files/mobs_redo/api.lua @@ -665,6 +665,8 @@ end -- drop items function mob_class:item_drop() + local pos = self.object:get_pos() + self.drops = type(self.drops) == "function" and self.drops(pos) or self.drops -- check for nil or no drops if not self.drops or #self.drops == 0 then @@ -682,7 +684,6 @@ function mob_class:item_drop() and self.cause_of_death.puncher:is_player() or nil local obj, item, num - local pos = self.object:get_pos() for n = 1, #self.drops do diff --git a/games/default/files/mobs_redo/depends.txt b/games/default/files/mobs_redo/depends.txt index 331d858ce..dd144eb16 100644 --- a/games/default/files/mobs_redo/depends.txt +++ b/games/default/files/mobs_redo/depends.txt @@ -1 +1,2 @@ -default \ No newline at end of file +default +experience?