<commit_before>--[[
Illarion Server

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
]]

local common = require("base.common")

local M = {}

local allTraits = {}

local function getSpendableTraitPoints(character)
    return character:getQuestProgress(720)
end

local function removeTraitPoints(character, amount)
    amount = amount or 1
    character:setQuestProgress(720, character:getQuestProgress(720)-1)
end

local function hasTrait(character, traitTable)
    return character:getQuestProgress(traitTable.questId) > 0
end

local function setTrait(character, traitTable)
    character:setQuestProgress(traitTable.questId, 1)
end

local function removeTrait(character, traitTable)
    character:setQuestProgress(traitTable.questId, 0)
end

local function fulfillsPrequisite(character, traitTable)
    if type(traitTable.prerequisiteFunction) == "function" then
        return traitTable.prerequisiteFunction(character)
    else
        return true
    end
end

local function getAllTraitsOfCharacter(character)
    local characterTraits = {}
    for _, traitTable in pairs(allTraits) do
        if hasTrait(character, traitTable) then
            table.insert(characterTraits, traitTable)
        end
    end
    return characterTraits
end

-- Trait categoris --
local GENERAL = 1
local FIGHTING = 2
local CRAFTING = 3
local GATHERING = 4
local MAGIC = 5
local ALCHEMY = 6
local FAITH = 7

local categoriesProperties = {

    [GENERAL] = {nameDe = "Allgemeine Eigeneschaften", nameEn = "General traits", icon = Item.treasureChestOpen},
    [FIGHTING] = {nameDe = "Kmpfereigenschaften", nameEn = "Fighter traits", icon = Item.serinjahSword},
    [CRAFTING] = {nameDe = "Handwerkereigenschaften", nameEn = "Crafter traits", icon = Item.hammer},
    [GATHERING] = {nameDe = "Arbeitereigenschaften", nameEn = "Worker traits", icon = Item.pickaxe},
    [MAGIC] = {nameDe = "Magiereigenschaften", nameEn = "Mage traits", icon = Item.wandOfFire},
    [ALCHEMY] = {nameDe = "Alchemisteneigenschaften", nameEn = "Alchemist trait", icon = Item.cauldronEmpty},
    --[FAITH] = {nameDe = "Glaubenseigenschaften", nameEn = "Faith traits", icon = Item.altarGrey}
    
}

-- GENERAL TRAITS --
M.PASSIVE_INCOME_I = {questId = 721, nameDe = "Passives Einkommen I", nameEn = "Passive income I", descriptionDe = "Jeden Monat erhlst du einen kleinen Geldbetrag aus deinen Quellen.", descriptionEn = "Every month, your sources grant you a small amount of money.", icon = Item.silverCoins, category = GENERAL, prerequisiteFunction = false}
table.insert(allTraits, M.PASSIVE_INCOME_I)

M.PASSIVE_INCOME_II = {questId = 722, nameDe = "Passives Einkommen II", nameEn = "Passive income II", descriptionDe = "Deine Quellen lassen dir einen greren Beitrag zukommen. \n[Voraussetzung: Passives Einkommen I]", descriptionEn = "Your sources grant you a bigger amount of money. \n[Prerequisite: Passive income I]", icon = Item.goldCoins, category = GENERAL, prerequisiteFunction = function(character) return hasTrait(character, M.PASSIVE_INCOME_I) end}
table.insert(allTraits, M.PASSIVE_INCOME_II)

M.WILFUL_HAIR = {questId = 723, nameDe = "<NAME>", nameEn = "<NAME>", descriptionDe = "Dein Haar hat Charakter. Das zeigt es jeden Tag aufs Neue, indem es eine andere Farbe annimmt.", descriptionEn = "Your hair has its own will. This is proofen by it changing its colour every day to a new colour.", icon = Item.redDye, category = GENERAL, prerequisiteFunction = false}
table.insert(allTraits, M.WILFUL_HAIR)
-- GENERAL TRAITS END --

-- FIGHTING TRAITS --
M.SWORD_MASTER = {questId = 724, nameDe = "<NAME>", nameEn = "Way of the sword", descriptionDe = "Du hast eine besondere Verbindung zum Schwert. In deiner Hand ist die Schwertklinge noch tdlicher. \n[Voraussetzung: Umgang mit den besten Schwertern]", descriptionEn = "You have a special connection to swords. In your hand, the blade of the sword becomes even more deadly. \n[Prerequisite: BE able to use the bests swords.]", icon = Item.magicalBroadsword, category = FIGHTING, prerequisiteFunction = function(character) return character:getSkill(Character.slashingWeapons) == 100 end}
table.insert(allTraits, M.SWORD_MASTER)

M.UNDEAD_FIGHTER = {questId = 725, nameDe = "Ttet die Toten!", nameEn = "Kill the dead!", descriptionDe = "Du kennst die Untoten und du weit, wie sie zu bekmpfen sind. Was auch immer die Quelle deiner Kraft ist - mge es Wissenschaft, Glaube oder etwas ganz anderes sein - du fgst ihnen mehr Schaden zu.", descriptionEn = "You know the undead, and you know how to fight them. Whatever your sources of power is - be it science, be it faith, or somehting else - you do more damage to them.", icon = Item.skullSouth, category = FIGHTING, prerequisiteFunction = false}
table.insert(allTraits, M.UNDEAD_FIGHTER)
-- FIGHTING TRAITS END --

-- CRAFTING TRAITS --
M.CARPENTRY_MASTER = {questId = 726, nameDe = "Ein Knstler mit dem Schnitzmessers", nameEn = "An artist with the carving knife", descriptionDe = "Durch auerordentliche Begabung fr Holzarbeiten kennst du so manches Geheimnis. Du kannst Schreinerarbeiten herstellen, die dem gewhnlichen Schreiner verschlossen bleiben.", descriptionEn = "Due to your special talent for wood work, you know some secrets. You are able to carve things which ordinary carpenters aren't able to produce.", icon = Item.carvingTools, category = CRAFTING, prerequisiteFunction = function(character) return character:getSkill(Character.carpentry) == 100 end}
table.insert(allTraits, M.CARPENTRY_MASTER)
-- CRAFTING TRAITS END --

-- GATHERING TRAITS --
M.BARE_HANDS_DIGGING = {questId = 727, nameDe = "Schaufel? Hnde!", nameEn = "Shovel? Hands!", descriptionDe = "Deine Hnde sind wie natrliche Schaufeln. Du kannst mit ihnen nach Sand, Lehm und Schtzen graben!", descriptionEn = "Your hands are like natural shovels. You can dig with them for sand, clay and treasures!", icon = Item.shovel, category = GATHERING, prerequisiteFunction = false}
table.insert(allTraits, M.BARE_HANDS_DIGGING)
-- GATHERING TRAITS END--

-- MAGIC TRAITS --
M.INCREASED_WAND_RANGE = {questId = 728, nameDe = "<NAME>", nameEn = "Extended wand magic", descriptionDe = "Eine besondere Einsicht in die Art und Weise wie deine Stabmagie funktioniert, erlaubt es dir einen Schritt weiter zu zaubern als andere. \n[Voraussetzung: Sei ein Magier.]", descriptionEn = "A special insight into the workings of your wand magic allows you to cast magic one step farther than others can. \n[Prerequisite: Be a mage.]", icon = Item.wandOfSpirit, category = MAGIC, prerequisiteFunction = function(character) return character:getMagicType() == 0 and (character:getQuestProgress(37) ~= 0 or character:getMagicFlags(0) > 0) end}
table.insert(allTraits, M.INCREASED_WAND_RANGE)
-- MAGIC TRAITS END --

-- ALCHEMY TRAITS --
M.UNSTABLE_POTIONS_MADE_STABLE = {questId = 729, nameDe = "Stabilisierte Instabilitt", nameEn = "Stabilised instability", descriptionDe = "Die Chance, dass die ebenso mchtigen wie instabilen Trnke explodieren, ist deutlich reduziert. \n[Voraussetzung: Sei ein Alchemist.]", descriptionEn = "The chance that those powerful, but instable potions explode is considerably reduced.\n[Voraussetzung: Be an alchemist.]", icon = Item.lightBlueSparklingPotion, category = ALCHEMY, prerequisiteFunction = function(character) return getMagicType() == 3 end}
table.insert(allTraits, M.UNSTABLE_POTIONS_MADE_STABLE)
-- ALCHEMY TRAIT END

local TRAIT_MANAGING_START = 1
local DISPLAY_ALL_OWN_TRAITS = 2
local DISPLAY_OWNED_TRAIT_DETAILS = 3
local DISPLAY_ALL_TRAIT_CATEGORIES = 4
local DISPLAY_ALL_TRAITS_FROM_SELECTED_CATEGORY = 5
local DISPLAY_SELECTED_UNOWNED_TRAIT_DETAILS = 6
local PLAYER_WANTS_TRAIT = 7

function M.traitsManagement(user, state, selectedTraitTable, selectedCategory)
    
    state = state or TRAIT_MANAGING_START
    
    if state == TRAIT_MANAGING_START then
        
        local buttonCharacterTraits = {icon = Item.blackBookSmall, text = common.GetNLS(user, "Zeige Charaktereigenschaften des Charakters an", "Display the character's traits"), func = M.traitsManagement, args = {user, DISPLAY_ALL_OWN_TRAITS}}
        local buttonAllTraits = {icon = Item.pileOfBooksSmall, text = common.GetNLS(user, "Zeige alle mglichen Charaktereigenschaften an", "Display all possible traits"), func = M.traitsManagement, args = {user, DISPLAY_ALL_TRAIT_CATEGORIES}}
        
        common.selectionDialogWrapper(user, common.GetNLS(user, "Charactereigenschaften", "Character traits"), common.GetNLS(user, "Hier kannst du dir die speziellen Eigenschaften deines Charakters anzeigen lassen oder neue hinzufgen.\n\nDu kannst noch" .. getSpendableTraitPoints(user) .. " Eigenschaften fr deinen Charakter auswhlen.", "Here you can look at the special traits of your character or add new to traits them.\n\nYou have " .. getSpendableTraitPoints(user) .. " traits left you can add."), {buttonCharacterTraits, buttonAllTraits}, nil, true)
    
    elseif state == DISPLAY_ALL_OWN_TRAITS then<commit_msg>getMagicType() is a member function of character<commit_after>--[[
Illarion Server

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
]]

local common = require("base.common")

local M = {}

local allTraits = {}

local function getSpendableTraitPoints(character)
    return character:getQuestProgress(720)
end

local function removeTraitPoints(character, amount)
    amount = amount or 1
    character:setQuestProgress(720, character:getQuestProgress(720)-1)
end

local function hasTrait(character, traitTable)
    return character:getQuestProgress(traitTable.questId) > 0
end

local function setTrait(character, traitTable)
    character:setQuestProgress(traitTable.questId, 1)
end

local function removeTrait(character, traitTable)
    character:setQuestProgress(traitTable.questId, 0)
end

local function fulfillsPrequisite(character, traitTable)
    if type(traitTable.prerequisiteFunction) == "function" then
        return traitTable.prerequisiteFunction(character)
    else
        return true
    end
end

local function getAllTraitsOfCharacter(character)
    local characterTraits = {}
    for _, traitTable in pairs(allTraits) do
        if hasTrait(character, traitTable) then
            table.insert(characterTraits, traitTable)
        end
    end
    return characterTraits
end

-- Trait categoris --
local GENERAL = 1
local FIGHTING = 2
local CRAFTING = 3
local GATHERING = 4
local MAGIC = 5
local ALCHEMY = 6
local FAITH = 7

local categoriesProperties = {

    [GENERAL] = {nameDe = "Allgemeine Eigeneschaften", nameEn = "General traits", icon = Item.treasureChestOpen},
    [FIGHTING] = {nameDe = "Kmpfereigenschaften", nameEn = "Fighter traits", icon = Item.serinjahSword},
    [CRAFTING] = {nameDe = "Handwerkereigenschaften", nameEn = "Crafter traits", icon = Item.hammer},
    [GATHERING] = {nameDe = "Arbeitereigenschaften", nameEn = "Worker traits", icon = Item.pickaxe},
    [MAGIC] = {nameDe = "Magiereigenschaften", nameEn = "Mage traits", icon = Item.wandOfFire},
    [ALCHEMY] = {nameDe = "Alchemisteneigenschaften", nameEn = "Alchemist trait", icon = Item.cauldronEmpty},
    --[FAITH] = {nameDe = "Glaubenseigenschaften", nameEn = "Faith traits", icon = Item.altarGrey}
    
}

-- GENERAL TRAITS --
M.PASSIVE_INCOME_I = {questId = 721, nameDe = "Passives Einkommen I", nameEn = "Passive income I", descriptionDe = "Jeden Monat erhlst du einen kleinen Geldbetrag aus deinen Quellen.", descriptionEn = "Every month, your sources grant you a small amount of money.", icon = Item.silverCoins, category = GENERAL, prerequisiteFunction = false}
table.insert(allTraits, M.PASSIVE_INCOME_I)

M.PASSIVE_INCOME_II = {questId = 722, nameDe = "Passives Einkommen II", nameEn = "Passive income II", descriptionDe = "Deine Quellen lassen dir einen greren Beitrag zukommen. \n[Voraussetzung: Passives Einkommen I]", descriptionEn = "Your sources grant you a bigger amount of money. \n[Prerequisite: Passive income I]", icon = Item.goldCoins, category = GENERAL, prerequisiteFunction = function(character) return hasTrait(character, M.PASSIVE_INCOME_I) end}
table.insert(allTraits, M.PASSIVE_INCOME_II)

M.WILFUL_HAIR = {questId = 723, nameDe = "Eigenwilliges Haar", nameEn = "Wilful hair", descriptionDe = "Dein Haar hat Charakter. Das zeigt es jeden Tag aufs Neue, indem es eine andere Farbe annimmt.", descriptionEn = "Your hair has its own will. This is proofen by it changing its colour every day to a new colour.", icon = Item.redDye, category = GENERAL, prerequisiteFunction = false}
table.insert(allTraits, M.WILFUL_HAIR)
-- GENERAL TRAITS END --

-- FIGHTING TRAITS --
M.SWORD_MASTER = {questId = 724, nameDe = "<NAME>es", nameEn = "Way of the sword", descriptionDe = "Du hast eine besondere Verbindung zum Schwert. In deiner Hand ist die Schwertklinge noch tdlicher. \n[Voraussetzung: Umgang mit den besten Schwertern]", descriptionEn = "You have a special connection to swords. In your hand, the blade of the sword becomes even more deadly. \n[Prerequisite: BE able to use the bests swords.]", icon = Item.magicalBroadsword, category = FIGHTING, prerequisiteFunction = function(character) return character:getSkill(Character.slashingWeapons) == 100 end}
table.insert(allTraits, M.SWORD_MASTER)

M.UNDEAD_FIGHTER = {questId = 725, nameDe = "Ttet die Toten!", nameEn = "Kill the dead!", descriptionDe = "Du kennst die Untoten und du weit, wie sie zu bekmpfen sind. Was auch immer die Quelle deiner Kraft ist - mge es Wissenschaft, Glaube oder etwas ganz anderes sein - du fgst ihnen mehr Schaden zu.", descriptionEn = "You know the undead, and you know how to fight them. Whatever your sources of power is - be it science, be it faith, or somehting else - you do more damage to them.", icon = Item.skullSouth, category = FIGHTING, prerequisiteFunction = false}
table.insert(allTraits, M.UNDEAD_FIGHTER)
-- FIGHTING TRAITS END --

-- CRAFTING TRAITS --
M.CARPENTRY_MASTER = {questId = 726, nameDe = "Ein Knstler mit dem Schnitzmessers", nameEn = "An artist with the carving knife", descriptionDe = "Durch auerordentliche Begabung fr Holzarbeiten kennst du so manches Geheimnis. Du kannst Schreinerarbeiten herstellen, die dem gewhnlichen Schreiner verschlossen bleiben.", descriptionEn = "Due to your special talent for wood work, you know some secrets. You are able to carve things which ordinary carpenters aren't able to produce.", icon = Item.carvingTools, category = CRAFTING, prerequisiteFunction = function(character) return character:getSkill(Character.carpentry) == 100 end}
table.insert(allTraits, M.CARPENTRY_MASTER)
-- CRAFTING TRAITS END --

-- GATHERING TRAITS --
M.BARE_HANDS_DIGGING = {questId = 727, nameDe = "Schaufel? Hnde!", nameEn = "Shovel? Hands!", descriptionDe = "Deine Hnde sind wie natrliche Schaufeln. Du kannst mit ihnen nach Sand, Lehm und Schtzen graben!", descriptionEn = "Your hands are like natural shovels. You can dig with them for sand, clay and treasures!", icon = Item.shovel, category = GATHERING, prerequisiteFunction = false}
table.insert(allTraits, M.BARE_HANDS_DIGGING)
-- GATHERING TRAITS END--

-- MAGIC TRAITS --
M.INCREASED_WAND_RANGE = {questId = 728, nameDe = "Verlngerte Stabmagie", nameEn = "Extended wand magic", descriptionDe = "Eine besondere Einsicht in die Art und Weise wie deine Stabmagie funktioniert, erlaubt es dir einen Schritt weiter zu zaubern als andere. \n[Voraussetzung: Sei ein Magier.]", descriptionEn = "A special insight into the workings of your wand magic allows you to cast magic one step farther than others can. \n[Prerequisite: Be a mage.]", icon = Item.wandOfSpirit, category = MAGIC, prerequisiteFunction = function(character) return character:getMagicType() == 0 and (character:getQuestProgress(37) ~= 0 or character:getMagicFlags(0) > 0) end}
table.insert(allTraits, M.INCREASED_WAND_RANGE)
-- MAGIC TRAITS END --

-- ALCHEMY TRAITS --
M.UNSTABLE_POTIONS_MADE_STABLE = {questId = 729, nameDe = "Stabilisierte Instabilitt", nameEn = "Stabilised instability", descriptionDe = "Die Chance, dass die ebenso mchtigen wie instabilen Trnke explodieren, ist deutlich reduziert. \n[Voraussetzung: Sei ein Alchemist.]", descriptionEn = "The chance that those powerful, but instable potions explode is considerably reduced.\n[Voraussetzung: Be an alchemist.]", icon = Item.lightBlueSparklingPotion, category = ALCHEMY, prerequisiteFunction = function(character) return character:getMagicType() == 3 end}
table.insert(allTraits, M.UNSTABLE_POTIONS_MADE_STABLE)
-- ALCHEMY TRAIT END

local TRAIT_MANAGING_START = 1
local DISPLAY_ALL_OWN_TRAITS = 2
local DISPLAY_OWNED_TRAIT_DETAILS = 3
local DISPLAY_ALL_TRAIT_CATEGORIES = 4
local DISPLAY_ALL_TRAITS_FROM_SELECTED_CATEGORY = 5
local DISPLAY_SELECTED_UNOWNED_TRAIT_DETAILS = 6
local PLAYER_WANTS_TRAIT = 7

function M.traitsManagement(user, state, selectedTraitTable, selectedCategory)
    
    state = state or TRAIT_MANAGING_START
    
    if state == TRAIT_MANAGING_START then
        
        local buttonCharacterTraits = {icon = Item.blackBookSmall, text = common.GetNLS(user, "Zeige Charaktereigenschaften des Charakters an", "Display the character's traits"), func = M.traitsManagement, args = {user, DISPLAY_ALL_OWN_TRAITS}}
        local buttonAllTraits = {icon = Item.pileOfBooksSmall, text = common.GetNLS(user, "Zeige alle mglichen Charaktereigenschaften an", "Display all possible traits"), func = M.traitsManagement, args = {user, DISPLAY_ALL_TRAIT_CATEGORIES}}
        
        common.selectionDialogWrapper(user, common.GetNLS(user, "Charactereigenschaften", "Character traits"), common.GetNLS(user, "Hier kannst du dir die speziellen Eigenschaften deines Charakters anzeigen lassen oder neue hinzufgen.\n\nDu kannst noch" .. getSpendableTraitPoints(user) .. " Eigenschaften fr deinen Charakter auswhlen.", "Here you can look at the special traits of your character or add new to traits them.\n\nYou have " .. getSpendableTraitPoints(user) .. " traits left you can add."), {buttonCharacterTraits, buttonAllTraits}, nil, true)
    
    elseif state == DISPLAY_ALL_OWN_TRAITS then
{'fraction_non_alphanumeric': 0.08845631979960338, 'fraction_numerical': 0.0072017534704101865, 'mean_word_length': 4.943858560794045, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5062376', 'n_tokens_mistral': 6251, 'n_tokens_neox': 5980, 'n_words': 2008}