diff --git a/mods/ctf/ctf_classes/classes.lua b/mods/ctf/ctf_classes/classes.lua index 2f5528e..56f3856 100644 --- a/mods/ctf/ctf_classes/classes.lua +++ b/mods/ctf/ctf_classes/classes.lua @@ -28,7 +28,7 @@ ctf_classes.register("shooter", { color = "#c60", properties = { allow_grapples = true, - max_hp = 16, + max_hp = 15, initial_stuff = { "shooter_guns:rifle_loaded", diff --git a/mods/other/hudbars/API.md b/mods/other/hudbars/API.md new file mode 100644 index 0000000..ca6144a --- /dev/null +++ b/mods/other/hudbars/API.md @@ -0,0 +1,210 @@ +API documentation for the HUD bars mod +====================================== + +## Introduction +This API allows you to add, change, hide and unhide custom HUD bars for this mod. + +## Overview +To give you a *very* brief overview over this API, here is the basic workflow on how to add your own custom HUD bar: + +* Create images for your HUD bar +* Call `hb.register_hudbar` to make the definition of the HUD bar known to this mod +* Call `hb.init_hudbar` for each player for which you want to use previously defined HUD bar +* Use `hb.change_hudbar` whenever you need to change the values of a HUD bar of a certain player +* If you need it: Use `hb.hide_hudbar` and `hb.unhide_hudbar` to hide or unhide HUD bars of a certain player + +## The basic rules +In order to use this API, you should be aware of a few basic rules in order to understand it: + +* A HUD bar is an approximate graphical representation of the ratio of a current value and a maximum value, i.e. current health of 15 and maximum health of 20. A full HUD bar represents 100%, an empty HUD bar represents 0%. +* The current value must always be equal to or smaller then the maximum +* Both current value and maximum must not be smaller than 0 +* Both current value and maximum must be real numbers. So no NaN, infinity, etc. +* The HUD bar will be hidden if the maximum equals 0. This is intentional. +* The health and breath HUD bars are hardcoded. + +These are soft rules, the HUD bars mod will not enforce all of these. +But this mod has been programmed under the assumption that these rules are followed, for integrity. + +## Adding a HUD bar +To make a new HUD bar known to this mod, you need … + +* … an image of size 2×16 for the bar +* … an icon of size 16×16 (optional) +* … to register it with `hb.register_hudbar` + +### Bar image +The image for the bar will be repeated horizontally to denote the “value” of the HUD bar. +It **must** be of size 2×16. +If neccessary, the image will be split vertically in half, and only the left half of the image +is displayed. So the final HUD bar will always be displayed on a per-pixel basis. + +The default bar images are single-colored, but you can use other styles as well, for instance, +a vertical gradient. + +### Icon +A 16×16 image shown left of the HUD bar. This is optional. + +### `hb.register_hudbar(identifier, text_color, label, textures, default_start_value, default_start_max, default_start_hidden, format_string, format_string_config)` +This function registers a new custom HUD bar definition to the HUD bars mod, so it can be later used to be displayed, changed, hidden +and unhidden on a per-player basis. +Note this does not yet display the HUD bar. + +The HUD bars will be displayed in a “first come, first serve” order. This API does not allow fow a custom order or a way to set it +manually in a reliable way. However, you can use the setting `hudbars_sorting` for this. See the advanced setting menu in Minetest +for more information. + + +#### Parameters +* `identifier`: A globally unique internal name for the HUD bar, will be used later to refer to it. Please only rely on alphanumeric characters for now. The identifiers “`health`” and “`breath`” are used internally for the built-in health and breath bar, respectively. Please do not use these names. +* `text_color`: A 3-octet number defining the color of the text. The octets denote, in this order red, green and blue and range from `0x00` (complete lack of this component) to `0xFF` (full intensity of this component). Example: `0xFFFFFF` for white. +* `label`: A string which is displayed on the HUD bar itself to describe the HUD bar. Try to keep this string short. +* `textures`: A table with the following fields: + * `bar`: The file name of the bar image (as string). This is only used for the `progress_bar` bar type (see `README.txt`, settings section). + * `icon`: The file name of the icon, as string. For the `progress_bar` type, it is shown as single image left of the bar, for the two statbar bar types, it is used as the statbar icon and will be repeated. This field can be `nil`, in which case no icon will be used, but this is not recommended, because the HUD bar will be invisible if the one of the statbar bar types is used. + * `bgicon`: The file name of the background icon, it is used as the background for the modern statbar mode only. This field can be `nil`, in which case no background icon will be displayed in this mode. +* `default_start_value`: If this HUD bar is added to a player, and no initial value is specified, this value will be used as initial current value +* `default_max_value`: If this HUD bar is added to a player, and no initial maximum value is specified, this value will be used as initial maximum value +* `default_start_hidden`: The HUD bar will be initially start hidden by default when added to a player. Use `hb.unhide_hudbar` to unhide it. +* `format_string`: Optional; You can specify an alternative format string to use for the final text on the HUD bar. The default format string is “`@1: @2/@3`” (The “@” numbers are placeholders that have a meaning in this order: @1 = Label, @2 = current value, @3 = maximum value). Do *not* use minetest.translator on this string, the string will be translated by `hudbars`, but you still must put this string into the translation catalogue file. +* `format_string_config`: Required if `format_string` is set. This allows to change which parameters to use in the format string. It's a table with these fields: + * `textdomain`: Text domain of the format string, used by `minetest.translate` + * `order`: Table that contains the order of the placeholders. It's also possible to remove placeholders. Default order: `{ "label", "value", "max_value" }` + * `format_value`: Format string to apply when displaying `value`. Syntax is same as in `string.format`. Default: `"%d"` + * `format_max_value`: Same as `format_value` but is applied to `max_value` + +#### Example +Example (mostly) from `hbarmor` mod: + +``` +hb.register_hudbar("armor", 0xFFFFFF, minetest.translator("hbarmor", "Armor"), { icon = "hbarmor_icon.png", bgicon = "hbarmor_bgicon.png", bar = "hbarmor_bar.png" }, 0, 100, hbarmor.autohide, N("@1: @2%"), { order = { "label", "value" }, textdomain = "hbarmor" } ) +``` + +Displays an armor HUD bar with a label of the form „Armor: 53%“. (`N` is a dummy function that returns its argument, used to make the string visible for translator scripts.) + +#### Return value +Always `nil`. + + +## Displaying a HUD bar +After a HUD bar has been registered, they are not yet displayed yet for any player. HUD bars must be +explicitly initialized on a per-player basis. + +You probably want to do this in the `minetest.register_on_joinplayer`. + +### `hb.init_hudbar(player, identifier, start_value, start_max, start_hidden)` +This function initialzes and activates a previously registered HUD bar and assigns it to a +certain client/player. This has only to be done once per player and after that, you can change +the values using `hb.change_hudbar`. + +However, if `start_hidden` was set to `true` for the HUD bar (in `hb.register_hudbar`), the HUD bar +will initially be hidden, but the HUD elements are still sent to the client. Otherwise, +the HUD bar will be initially be shown to the player. + +#### Parameters +* `player`: `ObjectRef` of the player to which the new HUD bar should be displayed to. +* `identifier`: The identifier of the HUD bar type, as specified in `hb.register_hudbar`. +* `start_value`: The initial current value of the HUD bar. This is optional, `default_start_value` of the registration function will be used, if this is `nil`. +* `start_max`: The initial maximum value of the HUD bar. This is optional, `default_start_max` of the registration function will be used, if this is `nil` +* `start_hidden`: Whether the HUD bar is initially hidden. This is optional, `default_start_hidden` of the registration function will be used as default + +#### Return value +`true` on success, `false` otherwise. + + +## Modifying a HUD bar +After a HUD bar has been added, you can change the current and maximum value and other attributes on a per-player basis. +You use the function `hb.change_hudbar` for this. + +### `hb.change_hudbar(player, identifier, new_value, new_max_value, new_icon, new_bgicon, new_bar, new_label, new_text_color)` +Changes the values and the appearance of an initialized HUD bar for a certain player. `new_value` +and `new_max_value` are the most important parameters as they specify the new current and maximum new values, you do not need +to worry too much about the other parameters. + +The following parameters are less important and provided for styling the HUD bar after registration (if +this is desired). The “styling” parameters parallel the parameters of `hb.register_hudbar`. It is +recommended to not change the style of a HUD bar too often as this can be distracting or confusing +for players. + +`new_value`, `new_max_value` `new_icon`, `new_bgicon`, `new_bar`, `new_label` and `new_text_color` can be +`nil`; if one of them is `nil`, that means the value is unchanged. If all those values are `nil`, this +function is a no-op. + +This function tries to minimize the amount of calls to `hud_change` of the Minetest Lua API +(and thus, network traffic), when you only change the value and/or maximum value. In this case, +`hud_change` is only called if it is actually needed, e.g. when the actual length of the bar +or the displayed string changed, so you do not have to worry about it. There is, however, no +such network optimization for the “styling” parameters, so keep this in mind. + +#### Parameters +* `player`: `ObjectRef` of the player to which the HUD bar belongs to +* `identifier`: The identifier of the HUD bar type to change, as specified in `hb.register_hudbar`. +* `new_value`: The new current value of the HUD bar +* `new_max_value`: The new maximum value of the HUD bar +* `new_icon`: File name of the new icon +* `new_bgicon`: File name of the new background icon for the modern-style statbar +* `new_bar`: File name of the new bar segment image +* `new_label`: A new text label of the HUD bar. Note the format string still applies +* `new_text_color`: A 3-octet number defining the new color of the text. + +#### Return value +`true` on success, `false` otherwise. + + +## Hiding and unhiding a HUD bar +You can also hide custom HUD bars, meaning they will not be displayed for a certain player. You can still +use `hb.change_hudbar` on a hidden HUD bar, the new values will be correctly displayed after the HUD bar +has been unhidden. Both functions will only call `hud_change` if there has been an actual change to avoid +unneccessary traffic. + +Note that the hidden state of a HUD bar will *not* be saved by this mod on server shutdown, so you may need +to write your own routines for this or by setting the correct value for `start_hidden` when calling +`hb.init_hudbar`. + +### `hb.hide_hudbar(player, identifier)` +Hides the specified HUD bar from the screen of the specified player. + +#### Parameters +* `player`: `ObjectRef` of the player to which the HUD bar belongs to +* `identifier`: The identifier of the HUD bar type to hide, as specified in `hb.register_hudbar`. + +#### Return value +`true` on success, `false` otherwise. + + +### `hb.unhide_hudbar(player, identifier)` +Makes a previously hidden HUD bar visible again to a player. + +#### Parameters +* `player`: `ObjectRef` of the player to which the HUD bar belongs to +* `identifier`: The identifier of the HUD bar type to unhide, as specified in `hb.register_hudbar`. + +#### Return value +`true` on success, `false` otherwise. + + +## Reading HUD bar information +It is also possible to read information about existing HUD bars. + +### `hb.get_hudbar_state(player, identifier)` +Returns the current state of the active player's HUD bar. + +#### Parameters +* `player`: `ObjectRef` of the player to which the HUD bar belongs to +* `identifier`: The identifier of the HUD bar type to hide, as specified in `hb.register_hudbar`. + +#### Return value +On success, returns a table which holds information on the current state of the HUD bar. Note +the table is a deep copy of the internal HUD bar state, it is *not* a reference; the information +hold by the table is only true for the moment you called this function. The fields of this table are: + +* `value`: Current value of HUD bar. +* `max`: Current maximum value of HUD bar. +* `hidden`: Boolean denoting whether the HUD bar is hidden. +* `barlength`: The length of the HUD bar in pixels. This field is meaningless if the HUD bar is currently hidden. +* `text`: The text shown on the HUD bar. This fiels is meaningless if the HUD bar is currently hidden. + +If the player does not exist, returns `nil` instead. + +### `hb.get_hudbar_identifiers()` +Returns a table of all currently registered HUD bar identifiers. diff --git a/mods/other/hudbars/README.md b/mods/other/hudbars/README.md new file mode 100644 index 0000000..8e17eda --- /dev/null +++ b/mods/other/hudbars/README.md @@ -0,0 +1,62 @@ +# HUD bars + +## Description +This mod changes the HUD of Minetest. It replaces the default health and breath +symbols by horizontal colored bars with text showing the number. + +Furthermore, it enables other mods to add their own custom bars to the HUD, +this mod will place them accordingly. + +**Important**: Keep in mind if running a server with this mod, that the custom +position should be displayed correctly on every screen size. + +## Current version +The current version is 2.3.2. +It works for Minetest 5.3.0. + +This software uses [semantic versioning](http://semver.org), as defined by version 2.0.0 of the SemVer +standard. + +## Settings +This mod can be configured quite a bit. You can change HUD bar appearance, offsets, ordering, and more. +Use the advanced settings menu in Minetest for detailed configuration. + +## API +The API is used to add your own custom HUD bars. +Documentation for the API of this mod can be found in `API.md`. + +## Legal +### License of source code +Author: Wuzzy (2015) + +Also: This mod was forked from the “Better HUD” [hud] mod by BlockMen. + +Translations: + +* German: Wuzzy +* Portuguese: BrunoMine +* Turkish: admicos +* Dutch: kingoscargames +* Italian: Hamlet +* Malay: muhdnurhidayat +* Russian: Imk +* Spanish: wuniversales + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the MIT License. + +### Licenses of textures + +* `hudbars_icon_health.png`—celeron55 (CC BY-SA 3.0), modified by BlockMen +* `hudbars_bgicon_health.png`—celeron55 (CC BY-SA 3.0), modified by BlockMen +* `hudbars_icon_breath.png`—kaeza (MIT License), modified by BlockMen, modified again by Wuzzy +* `hudbars_bgicon_breath.png`—based on previous image, edited by Wuzzy (MIT License) +* `hudbars_bar_health.png`—Wuzzy (MIT License) +* `hudbars_bar_breath.png`—Wuzzy (MIT License) +* `hudbars_bar_background.png`—Wuzzy (MIT License) + +### License references + +* [CC-BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/) +* [MIT License](https://opensource.org/licenses/MIT) diff --git a/mods/other/hudbars/default_settings.lua b/mods/other/hudbars/default_settings.lua new file mode 100644 index 0000000..d2a325b --- /dev/null +++ b/mods/other/hudbars/default_settings.lua @@ -0,0 +1,48 @@ +-- (Hardcoded) default settings + +hb.settings.max_bar_length = 160 +hb.settings.statbar_length = 20 + +-- Statbar positions +hb.settings.pos_left = {} +hb.settings.pos_right = {} +hb.settings.start_offset_left = {} +hb.settings.start_offset_right= {} +hb.settings.pos_left.x = hb.load_setting("hudbars_pos_left_x", "number", 0.5) +hb.settings.pos_left.y = hb.load_setting("hudbars_pos_left_y", "number", 1) +hb.settings.pos_right.x = hb.load_setting("hudbars_pos_right_x", "number", 0.5) +hb.settings.pos_right.y = hb.load_setting("hudbars_pos_right_y", "number", 1) +hb.settings.bar_type = hb.load_setting("hudbars_bar_type", "string", "progress_bar", {"progress_bar", "statbar_classic", "statbar_modern"}) +if hb.settings.bar_type == "progress_bar" then + hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_offset_left_x", "number", -175) + hb.settings.start_offset_left.y = hb.load_setting("hudbars_start_offset_left_y", "number", -86) + hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_offset_right_x", "number", 15) + hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_offset_right_y", "number", -86) +else + hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_statbar_offset_left_x", "number", -265) + hb.settings.start_offset_left.y = hb.load_setting("hudbars_start_statbar_offset_left_y", "number", -90) + hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_statbar_offset_right_x", "number", 25) + hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_statbar_offset_right_y", "number", -90) +end +hb.settings.vmargin = hb.load_setting("hudbars_vmargin", "number", 24) +hb.settings.tick = hb.load_setting("hudbars_tick", "number", 0.1) + +-- Experimental setting: Changing this setting is not officially supported, do NOT rely on it! +hb.settings.forceload_default_hudbars = hb.load_setting("hudbars_forceload_default_hudbars", "bool", true) + +-- Misc. settings +hb.settings.alignment_pattern = hb.load_setting("hudbars_alignment_pattern", "string", "zigzag", {"zigzag", "stack_up", "stack_down"}) +hb.settings.autohide_breath = hb.load_setting("hudbars_autohide_breath", "bool", true) + +local sorting = minetest.settings:get("hudbars_sorting") +if sorting ~= nil then + hb.settings.sorting = {} + hb.settings.sorting_reverse = {} + for k,v in string.gmatch(sorting, "(%w+)=(%w+)") do + hb.settings.sorting[k] = tonumber(v) + hb.settings.sorting_reverse[tonumber(v)] = k + end +else + hb.settings.sorting = { ["health"] = 0, ["breath"] = 1 } + hb.settings.sorting_reverse = { [0] = "health", [1] = "breath" } +end diff --git a/mods/other/hudbars/init.lua b/mods/other/hudbars/init.lua new file mode 100644 index 0000000..6ddd4a0 --- /dev/null +++ b/mods/other/hudbars/init.lua @@ -0,0 +1,570 @@ +local S = minetest.get_translator("hudbars") +local N = function(s) return s end + +hb = {} + +hb.hudtables = {} + +-- number of registered HUD bars +hb.hudbars_count = 0 + +-- table which records which HUD bar slots have been “registered” so far; used for automatic positioning +hb.registered_slots = {} + +hb.settings = {} + +function hb.load_setting(sname, stype, defaultval, valid_values) + local sval + if stype == "string" then + sval = minetest.settings:get(sname) + elseif stype == "bool" then + sval = minetest.settings:get_bool(sname) + elseif stype == "number" then + sval = tonumber(minetest.settings:get(sname)) + end + if sval ~= nil then + if valid_values ~= nil then + local valid = false + for i=1,#valid_values do + if sval == valid_values[i] then + valid = true + end + end + if not valid then + minetest.log("error", "[hudbars] Invalid value for "..sname.."! Using default value ("..tostring(defaultval)..").") + return defaultval + else + return sval + end + else + return sval + end + else + return defaultval + end +end + +-- Load default settings +dofile(minetest.get_modpath("hudbars").."/default_settings.lua") + +local function player_exists(player) + return player ~= nil and player:is_player() +end + +local function make_label(format_string, format_string_config, label, start_value, max_value) + local params = {} + local order = format_string_config.order + for o=1, #order do + if order[o] == "label" then + table.insert(params, label) + elseif order[o] == "value" then + if format_string_config.format_value then + table.insert(params, string.format(format_string_config.format_value, start_value)) + else + table.insert(params, start_value) + end + elseif order[o] == "max_value" then + if format_string_config.format_max_value then + table.insert(params, string.format(format_string_config.format_max_value, max_value)) + else + table.insert(params, max_value) + end + end + end + local ret + if format_string_config.textdomain then + ret = minetest.translate(format_string_config.textdomain, format_string, unpack(params)) + else + ret = S(format_string, unpack(params)) + end + return ret +end + +-- Table which contains all players with active default HUD bars (only for internal use) +hb.players = {} + +function hb.value_to_barlength(value, max) + if max == 0 then + return 0 + else + if hb.settings.bar_type == "progress_bar" then + local x + if value < 0 then x=-0.5 else x = 0.5 end + local ret = math.modf((value/max) * hb.settings.max_bar_length + x) + return ret + else + local x + if value < 0 then x=-0.5 else x = 0.5 end + local ret = math.modf((value/max) * hb.settings.statbar_length + x) + return ret + end + end +end + +function hb.get_hudtable(identifier) + return hb.hudtables[identifier] +end + +function hb.get_hudbar_position_index(identifier) + if hb.settings.sorting[identifier] ~= nil then + return hb.settings.sorting[identifier] + else + local i = 0 + while true do + if hb.registered_slots[i] ~= true and hb.settings.sorting_reverse[i] == nil then + return i + end + i = i + 1 + end + end +end + +function hb.register_hudbar(identifier, text_color, label, textures, default_start_value, default_start_max, default_start_hidden, format_string, format_string_config) + minetest.log("action", "hb.register_hudbar: "..tostring(identifier)) + local hudtable = {} + local pos, offset + local index = math.floor(hb.get_hudbar_position_index(identifier)) + hb.registered_slots[index] = true + if hb.settings.alignment_pattern == "stack_up" then + pos = hb.settings.pos_left + offset = { + x = hb.settings.start_offset_left.x, + y = hb.settings.start_offset_left.y - hb.settings.vmargin * index + } + elseif hb.settings.alignment_pattern == "stack_down" then + pos = hb.settings.pos_left + offset = { + x = hb.settings.start_offset_left.x, + y = hb.settings.start_offset_left.y + hb.settings.vmargin * index + } + else + if index % 2 == 0 then + pos = hb.settings.pos_left + offset = { + x = hb.settings.start_offset_left.x, + y = hb.settings.start_offset_left.y - hb.settings.vmargin * (index/2) + } + else + pos = hb.settings.pos_right + offset = { + x = hb.settings.start_offset_right.x, + y = hb.settings.start_offset_right.y - hb.settings.vmargin * ((index-1)/2) + } + end + end + if format_string == nil then + format_string = N("@1: @2/@3") + end + if format_string_config == nil then + format_string_config = {} + end + if format_string_config.order == nil then + format_string_config.order = { "label", "value", "max_value" } + end + if format_string_config.format_value == nil then + format_string_config.format_value = "%d" + end + if format_string_config.format_max_value == nil then + format_string_config.format_max_value = "%d" + end + + hudtable.add_all = function(player, hudtable, start_value, start_max, start_hidden) + if start_value == nil then start_value = hudtable.default_start_value end + if start_max == nil then start_max = hudtable.default_start_max end + if start_hidden == nil then start_hidden = hudtable.default_start_hidden end + local ids = {} + local state = {} + local name = player:get_player_name() + local bgscale, iconscale, text, barnumber, bgiconnumber + if start_max == 0 or start_hidden then + bgscale = { x=0, y=0 } + else + bgscale = { x=1, y=1 } + end + if start_hidden then + iconscale = { x=0, y=0 } + barnumber = 0 + bgiconnumber = 0 + text = "" + else + iconscale = { x=1, y=1 } + barnumber = hb.value_to_barlength(start_value, start_max) + bgiconnumber = hb.settings.statbar_length + text = make_label(format_string, format_string_config, label, start_value, start_max) + end + if hb.settings.bar_type == "progress_bar" then + ids.bg = player:hud_add({ + hud_elem_type = "image", + position = pos, + scale = bgscale, + text = "hudbars_bar_background.png", + alignment = {x=1,y=1}, + offset = { x = offset.x - 1, y = offset.y - 1 }, + z_index = 0, + }) + if textures.icon ~= nil then + ids.icon = player:hud_add({ + hud_elem_type = "image", + position = pos, + scale = iconscale, + text = textures.icon, + alignment = {x=-1,y=1}, + offset = { x = offset.x - 3, y = offset.y }, + z_index = 1, + }) + end + end + local bar_image, bgicon, bar_size + if hb.settings.bar_type == "progress_bar" then + bar_image = textures.bar + -- NOTE: Intentionally set to nil. For some reason, on some systems, + -- the progress bar is displaced when the bar_size is set explicitly here. + -- On the other hand, setting this to nil is deprecated in MT 5.0.0 due to + -- a debug log warning, but nothing is explained in lua_api.txt. + -- This section is a potential bug magnet, please watch with care! + -- The size of the bar image is expected to be exactly 2×16 pixels. + bar_size = nil + elseif hb.settings.bar_type == "statbar_classic" or hb.settings.bar_type == "statbar_modern" then + bar_image = textures.icon + bgicon = textures.bgicon + bar_size = {x=24, y=24} + end + local text2 + if hb.settings.bar_type == "statbar_modern" then + text2 = bgicon + end + ids.bar = player:hud_add({ + hud_elem_type = "statbar", + position = pos, + text = bar_image, + text2 = text2, + number = barnumber, + item = bgiconnumber, + alignment = {x=-1,y=-1}, + offset = offset, + direction = 0, + size = bar_size, + z_index = 1, + }) + if hb.settings.bar_type == "progress_bar" then + ids.text = player:hud_add({ + hud_elem_type = "text", + position = pos, + text = text, + alignment = {x=1,y=1}, + number = text_color, + direction = 0, + offset = { x = offset.x + 2, y = offset.y - 1}, + z_index = 2, + }) + end + -- Do not forget to update hb.get_hudbar_state if you add new fields to the state table + state.hidden = start_hidden + state.value = start_value + state.max = start_max + state.text = text + state.barlength = hb.value_to_barlength(start_value, start_max) + + local main_error_text = + "[hudbars] Bad initial values of HUD bar identifier “"..tostring(identifier).."” for player "..name..". " + + if start_max < start_value then + minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than start_value ("..start_value..")!") + end + if start_max < 0 then + minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than 0!") + end + if start_value < 0 then + minetest.log("error", main_error_text.."start_value ("..start_value..") is smaller than 0!") + end + + hb.hudtables[identifier].hudids[name] = ids + hb.hudtables[identifier].hudstate[name] = state + end + + hudtable.identifier = identifier + hudtable.format_string = format_string + hudtable.format_string_config = format_string_config + hudtable.label = label + hudtable.hudids = {} + hudtable.hudstate = {} + hudtable.default_start_hidden = default_start_hidden + hudtable.default_start_value = default_start_value + hudtable.default_start_max = default_start_max + + hb.hudbars_count= hb.hudbars_count + 1 + + hb.hudtables[identifier] = hudtable +end + +function hb.init_hudbar(player, identifier, start_value, start_max, start_hidden) + if not player_exists(player) then return false end + local hudtable = hb.get_hudtable(identifier) + hb.hudtables[identifier].add_all(player, hudtable, start_value, start_max, start_hidden) + return true +end + +function hb.change_hudbar(player, identifier, new_value, new_max_value, new_icon, new_bgicon, new_bar, new_label, new_text_color) + if new_value == nil and new_max_value == nil and new_icon == nil and new_bgicon == nil and new_bar == nil and new_label == nil and new_text_color == nil then + return true + end + if not player_exists(player) then + return false + end + + local name = player:get_player_name() + local hudtable = hb.get_hudtable(identifier) + if not hudtable.hudstate[name] then + return false + end + local value_changed, max_changed = false, false + + if new_value ~= nil then + if new_value ~= hudtable.hudstate[name].value then + hudtable.hudstate[name].value = new_value + value_changed = true + end + else + new_value = hudtable.hudstate[name].value + end + if new_max_value ~= nil then + if new_max_value ~= hudtable.hudstate[name].max then + hudtable.hudstate[name].max = new_max_value + max_changed = true + end + else + new_max_value = hudtable.hudstate[name].max + end + + if hb.settings.bar_type == "progress_bar" then + if new_icon ~= nil and hudtable.hudids[name].icon ~= nil then + player:hud_change(hudtable.hudids[name].icon, "text", new_icon) + end + if new_bgicon ~= nil and hudtable.hudids[name].bgicon ~= nil then + player:hud_change(hudtable.hudids[name].bgicon, "text", new_bgicon) + end + if new_bar ~= nil then + player:hud_change(hudtable.hudids[name].bar , "text", new_bar) + end + if new_label ~= nil then + hudtable.label = new_label + local new_text = make_label(hudtable.format_string, hudtable.format_string_config, new_label, hudtable.hudstate[name].value, hudtable.hudstate[name].max) + player:hud_change(hudtable.hudids[name].text, "text", new_text) + end + if new_text_color ~= nil then + player:hud_change(hudtable.hudids[name].text, "number", new_text_color) + end + else + if new_icon ~= nil and hudtable.hudids[name].bar ~= nil then + player:hud_change(hudtable.hudids[name].bar, "text", new_icon) + end + if new_bgicon ~= nil and hudtable.hudids[name].bg ~= nil then + player:hud_change(hudtable.hudids[name].bg, "text", new_bgicon) + end + end + + local main_error_text = + "[hudbars] Bad call to hb.change_hudbar, identifier: “"..tostring(identifier).."”, player name: “"..name.."”. " + if new_max_value < new_value then + minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than new_value ("..new_value..")!") + end + if new_max_value < 0 then + minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than 0!") + end + if new_value < 0 then + minetest.log("error", main_error_text.."new_value ("..new_value..") is smaller than 0!") + end + + if hudtable.hudstate[name].hidden == false then + if max_changed and hb.settings.bar_type == "progress_bar" then + if hudtable.hudstate[name].max == 0 then + player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0}) + else + player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1}) + end + end + + if value_changed or max_changed then + local new_barlength = hb.value_to_barlength(new_value, new_max_value) + if new_barlength ~= hudtable.hudstate[name].barlength then + player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(new_value, new_max_value)) + hudtable.hudstate[name].barlength = new_barlength + end + + if hb.settings.bar_type == "progress_bar" then + local new_text = make_label(hudtable.format_string, hudtable.format_string_config, hudtable.label, new_value, new_max_value) + if new_text ~= hudtable.hudstate[name].text then + player:hud_change(hudtable.hudids[name].text, "text", new_text) + hudtable.hudstate[name].text = new_text + end + end + end + end + return true +end + +function hb.hide_hudbar(player, identifier) + if not player_exists(player) then return false end + local name = player:get_player_name() + local hudtable = hb.get_hudtable(identifier) + if hudtable == nil then return false end + if hb.settings.bar_type == "progress_bar" then + if hudtable.hudids[name].icon ~= nil then + player:hud_change(hudtable.hudids[name].icon, "scale", {x=0,y=0}) + end + player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0}) + player:hud_change(hudtable.hudids[name].text, "text", "") + end + player:hud_change(hudtable.hudids[name].bar, "number", 0) + player:hud_change(hudtable.hudids[name].bar, "item", 0) + hudtable.hudstate[name].hidden = true + return true +end + +function hb.unhide_hudbar(player, identifier) + if not player_exists(player) then return false end + local name = player:get_player_name() + local hudtable = hb.get_hudtable(identifier) + if hudtable == nil then return false end + local value = hudtable.hudstate[name].value + local max = hudtable.hudstate[name].max + if hb.settings.bar_type == "progress_bar" then + if hudtable.hudids[name].icon ~= nil then + player:hud_change(hudtable.hudids[name].icon, "scale", {x=1,y=1}) + end + if hudtable.hudstate[name].max ~= 0 then + player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1}) + end + player:hud_change(hudtable.hudids[name].text, "text", make_label(hudtable.format_string, hudtable.format_string_config, hudtable.label, value, max)) + elseif hb.settings.bar_type == "statbar_modern" then + player:hud_change(hudtable.hudids[name].bar, "scale", {x=1,y=1}) + end + player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(value, max)) + player:hud_change(hudtable.hudids[name].bar, "item", hb.value_to_barlength(max, max)) + hudtable.hudstate[name].hidden = false + return true +end + +function hb.get_hudbar_state(player, identifier) + if not player_exists(player) then return nil end + local ref = hb.get_hudtable(identifier).hudstate[player:get_player_name()] + -- Do not forget to update this chunk of code in case the state changes + local copy = { + hidden = ref.hidden, + value = ref.value, + max = ref.max, + text = ref.text, + barlength = ref.barlength, + } + return copy +end + +function hb.get_hudbar_identifiers() + local ids = {} + for id, _ in pairs(hb.hudtables) do + table.insert(ids, id) + end + return ids +end + +--register built-in HUD bars +if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then + hb.register_hudbar("health", 0xFFFFFF, S("Health"), { bar = "hudbars_bar_health.png", icon = "hudbars_icon_health.png", bgicon = "hudbars_bgicon_health.png" }, 20, 20, false) + hb.register_hudbar("breath", 0xFFFFFF, S("Breath"), { bar = "hudbars_bar_breath.png", icon = "hudbars_icon_breath.png", bgicon = "hudbars_bgicon_breath.png" }, 10, 10, true) +end + +local function hide_builtin(player) + local flags = player:hud_get_flags() + flags.healthbar = false + flags.breathbar = false + player:hud_set_flags(flags) +end + + +local function custom_hud(player) + if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then + local hide + if minetest.settings:get_bool("enable_damage") then + hide = false + else + hide = true + end + local hp = player:get_hp() + local hp_max = player:get_properties().hp_max + hb.init_hudbar(player, "health", math.min(hp, hp_max), hp_max, hide) + local breath = player:get_breath() + local breath_max = player:get_properties().breath_max + local hide_breath + if breath >= breath_max and hb.settings.autohide_breath == true then hide_breath = true else hide_breath = false end + hb.init_hudbar(player, "breath", math.min(breath, breath_max), breath_max, hide_breath or hide) + end +end + +local function update_health(player) + local hp_max = player:get_properties().hp_max + hb.change_hudbar(player, "health", player:get_hp(), hp_max) +end + +-- update built-in HUD bars +local function update_hud(player) + if not player_exists(player) then return end + if minetest.settings:get_bool("enable_damage") then + if hb.settings.forceload_default_hudbars then + hb.unhide_hudbar(player, "health") + end + --air + local breath_max = player:get_properties().breath_max + local breath = player:get_breath() + + if breath >= breath_max and hb.settings.autohide_breath == true then + hb.hide_hudbar(player, "breath") + else + hb.unhide_hudbar(player, "breath") + hb.change_hudbar(player, "breath", math.min(breath, breath_max), breath_max) + end + --health + update_health(player) + elseif hb.settings.forceload_default_hudbars then + hb.hide_hudbar(player, "health") + hb.hide_hudbar(player, "breath") + end +end + +minetest.register_on_player_hpchange(function(player) + if hb.players[player:get_player_name()] ~= nil then + update_health(player) + end +end) + +minetest.register_on_respawnplayer(function(player) + update_health(player) + hb.hide_hudbar(player, "breath") +end) + +minetest.register_on_joinplayer(function(player) + hide_builtin(player) + custom_hud(player) + hb.players[player:get_player_name()] = player +end) + +minetest.register_on_leaveplayer(function(player) + hb.players[player:get_player_name()] = nil +end) + +local main_timer = 0 +local timer = 0 +minetest.register_globalstep(function(dtime) + main_timer = main_timer + dtime + timer = timer + dtime + if main_timer > hb.settings.tick or timer > 4 then + if main_timer > hb.settings.tick then main_timer = 0 end + -- only proceed if damage is enabled + if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then + for _, player in pairs(hb.players) do + -- update all hud elements + update_hud(player) + end + end + end + if timer > 4 then timer = 0 end +end) diff --git a/mods/other/hudbars/locale/hudbars.de.tr b/mods/other/hudbars/locale/hudbars.de.tr new file mode 100644 index 0000000..3d1e697 --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.de.tr @@ -0,0 +1,4 @@ +# textdomain: hudbars +Health=Leben +Breath=Atem +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/hudbars.es.tr b/mods/other/hudbars/locale/hudbars.es.tr new file mode 100644 index 0000000..bbf0279 --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.es.tr @@ -0,0 +1,4 @@ +# textdomain: hudbars +Health=Salud +Breath=Aliento +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/hudbars.it.tr b/mods/other/hudbars/locale/hudbars.it.tr new file mode 100644 index 0000000..3ada5b6 --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.it.tr @@ -0,0 +1,6 @@ +# textdomain: hudbars +Health=Salute +Breath=Ossigeno + +# Default format string for progress bar-style HUD bars, e.g. “Health 5/20” +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/hudbars.ms.tr b/mods/other/hudbars/locale/hudbars.ms.tr new file mode 100644 index 0000000..eb811ab --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.ms.tr @@ -0,0 +1,4 @@ +# textdomain: hudbars +Health=Kesihatan +Breath=Nafas +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/hudbars.nl.tr b/mods/other/hudbars/locale/hudbars.nl.tr new file mode 100644 index 0000000..b9c4a41 --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.nl.tr @@ -0,0 +1,6 @@ +# textdomain: hudbars +Health=Gezondheid +Breath=Adem + +# Default format string for progress bar-style HUD bars, e.g. “Health 5/20” +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/hudbars.pt.tr b/mods/other/hudbars/locale/hudbars.pt.tr new file mode 100644 index 0000000..a818f09 --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.pt.tr @@ -0,0 +1,6 @@ +# textdomain: hudbars +Health=Saude +Breath=Folego + +# Formato de string padrão para progresso bar-style de barras do HUD, por exemplo “Saude 5/20” +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/hudbars.ru.tr b/mods/other/hudbars/locale/hudbars.ru.tr new file mode 100644 index 0000000..2d278e3 --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.ru.tr @@ -0,0 +1,4 @@ +# textdomain: hudbars +Health=HP +Breath=дыхание +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/hudbars.tr.tr b/mods/other/hudbars/locale/hudbars.tr.tr new file mode 100644 index 0000000..6a2ce0b --- /dev/null +++ b/mods/other/hudbars/locale/hudbars.tr.tr @@ -0,0 +1,4 @@ +# textdomain: hudbars +Health=Can +Breath=Nefes +@1: @2/@3=@1: @2/@3 diff --git a/mods/other/hudbars/locale/template.txt b/mods/other/hudbars/locale/template.txt new file mode 100644 index 0000000..37b0559 --- /dev/null +++ b/mods/other/hudbars/locale/template.txt @@ -0,0 +1,6 @@ +# textdomain: hudbars +Health= +Breath= + +# Default format string for progress bar-style HUD bars, e.g. “Health 5/20” +@1: @2/@3= diff --git a/mods/other/hudbars/mod.conf b/mods/other/hudbars/mod.conf new file mode 100644 index 0000000..5fa238a --- /dev/null +++ b/mods/other/hudbars/mod.conf @@ -0,0 +1,2 @@ +name = hudbars +description = Replaces the health and breath symbols in the HUD by “progress bars” and shows exact values. Other mods can add more progress bars for custom player stats. diff --git a/mods/other/hudbars/screenshot.png b/mods/other/hudbars/screenshot.png new file mode 100644 index 0000000..88ee323 Binary files /dev/null and b/mods/other/hudbars/screenshot.png differ diff --git a/mods/other/hudbars/settingtypes.txt b/mods/other/hudbars/settingtypes.txt new file mode 100644 index 0000000..3e4390e --- /dev/null +++ b/mods/other/hudbars/settingtypes.txt @@ -0,0 +1,119 @@ +[Appearance] +# Specifies how the value indicators (i.e. health, breah, etc.) look. There are 3 styles +# available. You can choose between the default progress-bar-like bars and the good +# old statbars like you know from vanilla Minetest. +# These values are possible: +# - progress_bar: A horizontal progress-bar-like bar with a label, showing numerical value +# (current, maximum), and an icon. These bars usually convey the most +# information. This is the default and recommended value. +# - statbar_classic: Classic statbar, like in vanilla Minetest. Made out of up to 20 +# half-symbols. Those bars represent the vague ratio between +# the current value and the maximum value. 1 half-symbol stands for +# approximately 5% of the maximum value. +# - statbar_modern: Like the classic statbar, but also supports background images, this +# kind of statbar may be considered to be more user-friendly than the +# classic statbar. This bar type closely resembles the mod +# “Better HUD” [hud] by BlockMen. +hudbars_bar_type (HUD bars style) enum progress_bar progress_bar,statbar_classic,statbar_modern + + +# If enabled (default), the breath indicators in the HUD will be automatically hidden shortly +# after the breath has been filled up. Otherwise, the breath will always be displayed. +hudbars_autohide_breath (Automatically hide breath indicators) bool true + +# This setting changes the way the HUD bars are ordered on the display. You can choose +# between a zig-zag pattern (default) or a vertically stacked pattern. +# The following values are allowed: +# - zigzag: Starting from the left bottom, the next is right from the first, +# the next is above the first, the next is right of the third, etc. +# - stack_up: The HUD bars are stacked vertically, going upwards. +# - stack_down: The HUD bars are stacked vertically, going downwards. +hudbars_alignment_pattern (HUD bars alignment pattern) enum zigzag zigzag,stack_up,stack_down + +# This setting allows you to specify the order of the HUD bars explicitly. If left empty +# (the default), the health and breath indicators come first, additional indicators +# may appear in any order. This setting is quite technical and normal users probably do not +# need to worry about it. +# +# Syntax: +# The setting has to be specified as a comma-seperated list of key=value pairs, where a key +# refers to the identifier of a HUD bar and the value refers to the slot number of where the +# HUD bar should be placed. The slot number must be an integer greater of equal to 0. Where +# the HUD bars will be displayed exactly depends on the alignment pattern being used. +# All HUD bars to which no order value has been applied will fill in all slots which have +# not been occupied by the HUD bars specified in this setting, the slots will be filled in +# from the lowest slot number. +# Note that the order of those remaining HUD bars is not fixed, it basically just boils +# down on which mod “came” first. Don't worry, the mod will still work perfectly fine, this +# setting is entirely optional. +# The identifier for the health bar is “health” and the identifier for the breath bar is +# “breath”. For other HUD bars, you have to learn it from the mod which is supplying them. +# +# Be careful not to use slot indices twice, or else different HUD bars will be drawn over +# each other! +# +# Example: “breath=0, health=1” +# This makes the breath bar first and the health bar second, which is the opposite order +# of the default one. +hudbars_sorting (HUD bars order) string + +[Positions and offsets] +# Horizontal (x) main position of the HUD bars over the entire screen. +# 0.0 is left-most, 1.0 is right-most. +# For the zig-zag alignment pattern, this is for the left HUD bars. +hudbars_pos_left_x (Left HUD bar screen x position) float 0.5 0.0 1.0 +# Vertical (y) main position of the HUD bars over the entire screen. +# 0.0 is top, 1.0 is bottom. +# For the zig-zag alignment pattern, this is for the left HUD bars. +hudbars_pos_left_y (Left HUD bar screen y position) float 1.0 0.0 1.0 +# Horizontal (x) main position of the right HUD bars over the entire screen. +# 0.0 is left-most, 1.0 is right-most. +# Only used for the zig-zag alignment pattern. +hudbars_pos_right_x (Right HUD bar screen x position) float 0.5 0.0 1.0 +# Vertical main position (y) of the right HUD bars over the entire screen. +# 0.0 is top, 1.0 is bottom. +# Only used for the zig-zag alignment pattern. +hudbars_pos_right_y (Right HUD bar screen y position) float 1.0 0.0 1.0 + +# Precise x offset in pixels from the basic screen x position of the HUD bars. +# For the zig-zag alignment pattern, this is for the left HUD bars. +# This setting is used for the progress bar HUD bar style. +hudbars_start_offset_left_x (Left HUD bar x offset) int -175 +# Precise y offset in pixels from the basic screen y position of the HUD bars. +# For the zig-zag alignment pattern, this is for the left HUD bars. +# This setting is used for the progress bar HUD bar style. +hudbars_start_offset_left_y (Left HUD bar y offset) int -86 +# Precise x offset in pixels from the basic screen x position of the right HUD bars. +# Only used for the zig-zag alignment pattern. +# This setting is used for the progress bar HUD bar style. +hudbars_start_offset_right_x (Right HUD bar x offset) int 15 +# Precise y offset in pixels from the basic screen y position of the right HUD bars. +# Only used for the zig-zag alignment pattern. +# This setting is used for the progress bar HUD bar style. +hudbars_start_offset_right_y (Right HUD bar y offset) int -86 + +# Precise x offset in pixels from the basic screen x position of the HUD statbars. +# For the zig-zag alignment pattern, this is for the left HUD statbars. +# This setting is used for the classic and modern statbar styles. +hudbars_start_statbar_offset_left_x (Left HUD statbar x offset) int -265 +# Precise y offset in pixels from the basic screen y position of the HUD statbars. +# For the zig-zag alignment pattern, this is for the left HUD statbars. +# This setting is used for the classic and modern statbar styles. +hudbars_start_statbar_offset_left_y (Left HUD statbar y offset) int -90 +# Precise x offset in pixels from the basic screen x position of the right HUD statbars. +# Only used for the zig-zag alignment pattern. +# This setting is used for the classic and modern statbar styles. +hudbars_start_statbar_offset_right_x (Right HUD statbar x offset) int 25 +# Precise y offset in pixels from the basic screen y position of the right HUD statbars. +# Only used for the zig-zag alignment pattern. +# This setting is used for the classic and modern statbar styles. +hudbars_start_statbar_offset_right_y (Right HUD statbar y offset) int -90 + +# The vertical distance between two HUD bars, in pixels. +hudbars_vmargin (Vertical distance between HUD bars) int 24 0 + +[Performance] +# The of seconds which need to pass before the server updates the default HUD bars +# (health and breath). Increase this number if you have a slow server or a slow network +# connection and experience performance problems. +hudbars_tick (Default HUD bars update interval) float 0.1 0.0 4.0 diff --git a/mods/other/hudbars/textures/hudbars_bar_background.png b/mods/other/hudbars/textures/hudbars_bar_background.png new file mode 100644 index 0000000..cbc6c3f Binary files /dev/null and b/mods/other/hudbars/textures/hudbars_bar_background.png differ diff --git a/mods/other/hudbars/textures/hudbars_bar_breath.png b/mods/other/hudbars/textures/hudbars_bar_breath.png new file mode 100644 index 0000000..7d19a57 Binary files /dev/null and b/mods/other/hudbars/textures/hudbars_bar_breath.png differ diff --git a/mods/other/hudbars/textures/hudbars_bar_health.png b/mods/other/hudbars/textures/hudbars_bar_health.png new file mode 100644 index 0000000..6530916 Binary files /dev/null and b/mods/other/hudbars/textures/hudbars_bar_health.png differ diff --git a/mods/other/hudbars/textures/hudbars_bgicon_breath.png b/mods/other/hudbars/textures/hudbars_bgicon_breath.png new file mode 100644 index 0000000..176629a Binary files /dev/null and b/mods/other/hudbars/textures/hudbars_bgicon_breath.png differ diff --git a/mods/other/hudbars/textures/hudbars_bgicon_health.png b/mods/other/hudbars/textures/hudbars_bgicon_health.png new file mode 100644 index 0000000..e2be276 Binary files /dev/null and b/mods/other/hudbars/textures/hudbars_bgicon_health.png differ diff --git a/mods/other/hudbars/textures/hudbars_icon_breath.png b/mods/other/hudbars/textures/hudbars_icon_breath.png new file mode 100644 index 0000000..d1a5bcc Binary files /dev/null and b/mods/other/hudbars/textures/hudbars_icon_breath.png differ diff --git a/mods/other/hudbars/textures/hudbars_icon_health.png b/mods/other/hudbars/textures/hudbars_icon_health.png new file mode 100644 index 0000000..941e973 Binary files /dev/null and b/mods/other/hudbars/textures/hudbars_icon_health.png differ diff --git a/mods/other/sprint/init.lua b/mods/other/sprint/init.lua index c1dd642..0737339 100644 --- a/mods/other/sprint/init.lua +++ b/mods/other/sprint/init.lua @@ -12,7 +12,8 @@ if minetest.get_modpath("hudbars") ~= nil then hb.register_hudbar("sprint", 0xFFFFFF, "Stamina", { bar = "sprint_stamina_bar.png", icon = "sprint_stamina_icon.png" }, STAMINA_MAX, STAMINA_MAX, - false, "%s: %.1f/%.1f") + false + ) SPRINT_HUDBARS_USED = true else