diff --git a/serverdata/creation/attribute_limits.sdb b/serverdata/creation/attribute_limits.sdb new file mode 100644 index 000000000..a4f4af558 --- /dev/null +++ b/serverdata/creation/attribute_limits.sdb @@ -0,0 +1,12 @@ +male_template female_template min_health max_health min_strength max_strength min_constitution max_constitution min_action max_action min_quickness max_quickness min_stamina max_stamina min_mind max_mind min_focus max_focus min_willpower max_willpower total + +bothan_male bothan_female 900 900 0 0 850 850 1000 1000 0 0 1200 1200 1000 1000 0 0 950 950 5900 +human_male human_female 1000 1000 0 0 1000 1000 1000 1000 0 0 1000 1000 1000 1000 0 0 1000 1000 6000 +moncal_male moncal_female 900 900 0 0 850 850 1000 1000 0 0 950 950 1000 1000 0 0 1200 1200 5900 +rodian_male rodian_female 900 900 0 0 850 850 1000 1000 0 0 1300 1300 1000 1000 0 0 850 850 5900 +trandoshan_male trandoshan_female 1150 1150 0 0 1500 1500 1000 1000 0 0 850 850 1000 1000 0 0 900 900 6400 +twilek_male twilek_female 900 900 0 0 1050 1050 1000 1000 0 0 1100 1100 1000 1000 0 0 900 900 5950 +wookiee_male wookiee_female 1250 1250 0 0 1300 1300 1000 1000 0 0 950 950 1000 1000 0 0 1000 1000 6500 +zabrak_male zabrak_female 1100 1100 0 0 900 900 1000 1000 0 0 1000 1000 1000 1000 0 0 1100 1100 6100 +sullustan_male sullustan_female 1050 1050 0 0 900 900 1000 1000 0 0 1050 1050 1000 1000 0 0 1100 1100 6100 +ithorian_male ithorian_female 1300 1300 0 0 1200 1200 1000 1000 0 0 900 900 1000 1000 0 0 950 950 6350 diff --git a/serverdata/creation/profession_mods.sdb b/serverdata/creation/profession_mods.sdb new file mode 100644 index 000000000..087adaa21 --- /dev/null +++ b/serverdata/creation/profession_mods.sdb @@ -0,0 +1,9 @@ +profession health strength constitution action quickness stamina mind focus willpower + +crafting_artisan 1000 0 1000 1000 0 1000 1000 0 1000 +combat_brawler 1000 0 1000 1000 0 1000 1000 0 1000 +social_entertainer 1000 0 1000 1000 0 1000 1000 0 1000 +combat_marksman 1000 0 1000 1000 0 1000 1000 0 1000 +science_medic 1000 0 1000 1000 0 1000 1000 0 1000 +outdoors_scout 1000 0 1000 1000 0 1000 1000 0 1000 +jedi 1000 0 1000 1000 0 1000 1000 0 1000 diff --git a/serverdata/creation/racial_mods.sdb b/serverdata/creation/racial_mods.sdb new file mode 100644 index 000000000..2a1fab0b2 --- /dev/null +++ b/serverdata/creation/racial_mods.sdb @@ -0,0 +1,12 @@ +male_template female_template health strength constitution action quickness stamina mind focus willpower + +bothan_male bothan_female -100 0 -150 0 0 200 0 0 -50 +human_male human_female 0 0 0 0 0 0 0 0 0 +moncal_male moncal_female -100 0 -150 0 0 -50 0 0 200 +rodian_male rodian_female -100 0 -150 0 0 300 0 0 -150 +trandoshan_male trandoshan_female 150 0 500 0 0 -150 0 0 -100 +twilek_male twilek_female -100 0 50 0 0 100 0 0 -100 +wookiee_male wookiee_female 250 0 300 0 0 -50 0 0 0 +zabrak_male zabrak_female 100 0 -100 0 0 0 0 0 100 +sullustan_male sullustan_female 50 0 -100 0 0 50 0 0 100 +ithorian_male ithorian_female 300 0 200 0 0 -100 0 0 -50 diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationAttributeLimitsLoader.kt b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationAttributeLimitsLoader.kt new file mode 100644 index 000000000..b0074b0b0 --- /dev/null +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationAttributeLimitsLoader.kt @@ -0,0 +1,64 @@ +/*********************************************************************************** + * Copyright (c) 2026 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is an emulation project for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create one or more emulators which will provide servers for * + * players to continue playing a game similar to the one they used to play. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore 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. * + * * + * Holocore 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 Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.resources.support.data.server_info.loader + +import com.projectswg.common.data.encodables.tangible.Race +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet +import java.io.File +import java.io.IOException + +class CreationAttributeLimitsLoader internal constructor() : DataLoader() { + private val limitsByRace: MutableMap = HashMap() + + fun getLimits(race: Race): AttributeLimits? = limitsByRace[race] + + @Throws(IOException::class) + override fun load() { + SdbLoader.load(File("serverdata/creation/attribute_limits.sdb")).use { set -> + while (set.next()) { + val limits = AttributeLimits(set) + limitsByRace[Race.getRace(set.getText("male_template"))] = limits + limitsByRace[Race.getRace(set.getText("female_template"))] = limits + } + } + } + + class AttributeLimits(set: SdbResultSet) { + val minHealth: Int = set.getInt("min_health").toInt() + val maxHealth: Int = set.getInt("max_health").toInt() + val minConstitution: Int = set.getInt("min_constitution").toInt() + val maxConstitution: Int = set.getInt("max_constitution").toInt() + val minAction: Int = set.getInt("min_action").toInt() + val maxAction: Int = set.getInt("max_action").toInt() + val minStamina: Int = set.getInt("min_stamina").toInt() + val maxStamina: Int = set.getInt("max_stamina").toInt() + val minMind: Int = set.getInt("min_mind").toInt() + val maxMind: Int = set.getInt("max_mind").toInt() + val minWillpower: Int = set.getInt("min_willpower").toInt() + val maxWillpower: Int = set.getInt("max_willpower").toInt() + } +} diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationProfessionModsLoader.kt b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationProfessionModsLoader.kt new file mode 100644 index 000000000..0c2da0c72 --- /dev/null +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationProfessionModsLoader.kt @@ -0,0 +1,57 @@ +/*********************************************************************************** + * Copyright (c) 2026 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is an emulation project for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create one or more emulators which will provide servers for * + * players to continue playing a game similar to the one they used to play. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore 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. * + * * + * Holocore 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 Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.resources.support.data.server_info.loader + +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet +import java.io.File +import java.io.IOException + +class CreationProfessionModsLoader internal constructor() : DataLoader() { + private val modsByProfession: MutableMap = HashMap() + + fun getMods(profession: String): ProfessionMods? = modsByProfession[profession] + + @Throws(IOException::class) + override fun load() { + SdbLoader.load(File("serverdata/creation/profession_mods.sdb")).use { set -> + while (set.next()) { + val mods = ProfessionMods(set) + modsByProfession[mods.profession] = mods + } + } + } + + class ProfessionMods(set: SdbResultSet) { + val profession: String = set.getText("profession") + val health: Int = set.getInt("health").toInt() + val constitution: Int = set.getInt("constitution").toInt() + val action: Int = set.getInt("action").toInt() + val stamina: Int = set.getInt("stamina").toInt() + val mind: Int = set.getInt("mind").toInt() + val willpower: Int = set.getInt("willpower").toInt() + } +} diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationRacialModsLoader.kt b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationRacialModsLoader.kt new file mode 100644 index 000000000..aae9b1305 --- /dev/null +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CreationRacialModsLoader.kt @@ -0,0 +1,58 @@ +/*********************************************************************************** + * Copyright (c) 2026 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is an emulation project for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create one or more emulators which will provide servers for * + * players to continue playing a game similar to the one they used to play. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore 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. * + * * + * Holocore 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 Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.resources.support.data.server_info.loader + +import com.projectswg.common.data.encodables.tangible.Race +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet +import java.io.File +import java.io.IOException + +class CreationRacialModsLoader internal constructor() : DataLoader() { + private val modsByRace: MutableMap = HashMap() + + fun getMods(race: Race): RacialMods? = modsByRace[race] + + @Throws(IOException::class) + override fun load() { + SdbLoader.load(File("serverdata/creation/racial_mods.sdb")).use { set -> + while (set.next()) { + val mods = RacialMods(set) + modsByRace[Race.getRace(set.getText("male_template"))] = mods + modsByRace[Race.getRace(set.getText("female_template"))] = mods + } + } + } + + class RacialMods(set: SdbResultSet) { + val health: Int = set.getInt("health").toInt() + val constitution: Int = set.getInt("constitution").toInt() + val action: Int = set.getInt("action").toInt() + val stamina: Int = set.getInt("stamina").toInt() + val mind: Int = set.getInt("mind").toInt() + val willpower: Int = set.getInt("willpower").toInt() + } +} diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.kt b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.kt index 076501a0d..b831a4c33 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.kt +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.kt @@ -48,6 +48,9 @@ abstract class DataLoader { fun playerLevels(): PlayerLevelLoader = ServerData.playerLevels fun playerRoles(): PlayerRoleLoader = ServerData.playerRoles fun playerStartClothing(): StartClothingLoader = ServerData.playerStartClothing + fun creationAttributeLimits(): CreationAttributeLimitsLoader = ServerData.creationAttributeLimits + fun creationProfessionMods(): CreationProfessionModsLoader = ServerData.creationProfessionMods + fun creationRacialMods(): CreationRacialModsLoader = ServerData.creationRacialMods fun buildouts(): BuildoutLoader = buildouts(listOf()) fun buildouts(events: Collection): BuildoutLoader = BuildoutLoader.load(events) fun buildingCells(): BuildingCellLoader = ServerData.buildingCells diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/ServerData.kt b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/ServerData.kt index df2188381..da5104302 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/ServerData.kt +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/ServerData.kt @@ -60,6 +60,9 @@ object ServerData { val playerLevels by SoftDataLoaderDelegate(::PlayerLevelLoader) val playerRoles by SoftDataLoaderDelegate(::PlayerRoleLoader) val playerStartClothing by SoftDataLoaderDelegate(::StartClothingLoader) + val creationAttributeLimits by SoftDataLoaderDelegate(::CreationAttributeLimitsLoader) + val creationProfessionMods by SoftDataLoaderDelegate(::CreationProfessionModsLoader) + val creationRacialMods by SoftDataLoaderDelegate(::CreationRacialModsLoader) val staticItems by SoftDataLoaderDelegate(::StaticItemLoader) val performances by SoftDataLoaderDelegate(::PerformanceLoader) val combatXpMultipliers by SoftDataLoaderDelegate(::CombatXpMultiplierLoader) diff --git a/src/main/java/com/projectswg/holocore/resources/support/global/zone/creation/CharacterCreation.kt b/src/main/java/com/projectswg/holocore/resources/support/global/zone/creation/CharacterCreation.kt index 14d743ae0..74be5f442 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/global/zone/creation/CharacterCreation.kt +++ b/src/main/java/com/projectswg/holocore/resources/support/global/zone/creation/CharacterCreation.kt @@ -34,6 +34,9 @@ import com.projectswg.common.data.swgfile.ClientFactory import com.projectswg.common.network.packets.swg.login.creation.ClientCreateCharacter import com.projectswg.holocore.intents.gameplay.player.experience.GrantSkillIntent import com.projectswg.holocore.intents.support.objects.ObjectCreatedIntent +import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader.Companion.creationAttributeLimits +import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader.Companion.creationProfessionMods +import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader.Companion.creationRacialMods import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader.Companion.playerStartClothing import com.projectswg.holocore.resources.support.data.server_info.loader.TerrainZoneInsertionLoader.ZoneInsertion import com.projectswg.holocore.resources.support.global.player.AccessLevel @@ -55,6 +58,7 @@ class CharacterCreation(private val player: Player, private val create: ClientCr val creatureObj = createCreature(race.filename, info) val playerObj = createPlayer(creatureObj) + setCreationAttributes(creatureObj, race) setCreatureObjectValues(creatureObj, race) setPlayerObjectValues(playerObj, race) createHair(creatureObj, create.hair, create.hairCustomization) @@ -158,6 +162,39 @@ class CharacterCreation(private val player: Player, private val create: ClientCr createItem(creatureObj.inventory, "object/tangible/instrument/shared_slitherhorn.iff") } + private fun setCreationAttributes(creatureObj: CreatureObject, race: Race) { + val professionMods = creationProfessionMods().getMods(create.clothes) ?: return + val racialMods = creationRacialMods().getMods(race) ?: return + val limits = creationAttributeLimits().getLimits(race) ?: return + + val health = (professionMods.health + racialMods.health).coerceIn(limits.minHealth, limits.maxHealth) + val constitution = (professionMods.constitution + racialMods.constitution).coerceIn(limits.minConstitution, limits.maxConstitution) + val action = (professionMods.action + racialMods.action).coerceIn(limits.minAction, limits.maxAction) + val stamina = (professionMods.stamina + racialMods.stamina).coerceIn(limits.minStamina, limits.maxStamina) + val mind = (professionMods.mind + racialMods.mind).coerceIn(limits.minMind, limits.maxMind) + val willpower = (professionMods.willpower + racialMods.willpower).coerceIn(limits.minWillpower, limits.maxWillpower) + + creatureObj.setBaseHealth(health) + creatureObj.maxHealth = health + creatureObj.health = health + creatureObj.setBaseAction(action) + creatureObj.maxAction = action + creatureObj.action = action + creatureObj.setBaseMind(mind) + creatureObj.maxMind = mind + creatureObj.mind = mind + + creatureObj.setBaseConstitution(constitution) + creatureObj.maxConstitution = constitution + creatureObj.constitution = constitution + creatureObj.setBaseStamina(stamina) + creatureObj.maxStamina = stamina + creatureObj.stamina = stamina + creatureObj.setBaseWillpower(willpower) + creatureObj.maxWillpower = willpower + creatureObj.willpower = willpower + } + private fun createDefaultWeapon(creatureObj: CreatureObject): WeaponObject { val defWeapon = createDefaultWeapon() defWeapon.moveToContainer(creatureObj) diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java index 77830cd0a..c9a8d9347 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java @@ -921,6 +921,10 @@ public void setMaxAction(int maxAction) { creo6.setMaxAction(maxAction); } + public void setBaseMind(int baseMind) { + baseAttributes.setMind(baseMind); + } + public void setMind(int mind) { creo6.setMind(mind); } @@ -933,6 +937,78 @@ public void setMaxMind(int maxMind) { creo6.setMaxMind(maxMind); } + public int getConstitution() { + return creo6.getConstitution(); + } + + public int getBaseConstitution() { + return baseAttributes.getHealthRegen(); + } + + public void setBaseConstitution(int baseConstitution) { + baseAttributes.setHealthRegen(baseConstitution); + } + + public void setConstitution(int constitution) { + creo6.setConstitution(constitution); + } + + public int getMaxConstitution() { + return creo6.getMaxConstitution(); + } + + public void setMaxConstitution(int maxConstitution) { + creo6.setMaxConstitution(maxConstitution); + } + + public int getStamina() { + return creo6.getStamina(); + } + + public int getBaseStamina() { + return baseAttributes.getActionRegen(); + } + + public void setBaseStamina(int baseStamina) { + baseAttributes.setActionRegen(baseStamina); + } + + public void setStamina(int stamina) { + creo6.setStamina(stamina); + } + + public int getMaxStamina() { + return creo6.getMaxStamina(); + } + + public void setMaxStamina(int maxStamina) { + creo6.setMaxStamina(maxStamina); + } + + public int getWillpower() { + return creo6.getWillpower(); + } + + public int getBaseWillpower() { + return baseAttributes.getMindRegen(); + } + + public void setBaseWillpower(int baseWillpower) { + baseAttributes.setMindRegen(baseWillpower); + } + + public void setWillpower(int willpower) { + creo6.setWillpower(willpower); + } + + public int getMaxWillpower() { + return creo6.getMaxWillpower(); + } + + public void setMaxWillpower(int maxWillpower) { + creo6.setMaxWillpower(maxWillpower); + } + private void initBaseAttributes() { baseAttributes.setHealth(1000); baseAttributes.setAction(100); diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObjectSharedNP.java b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObjectSharedNP.java index e42f8ce65..881618263 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObjectSharedNP.java +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObjectSharedNP.java @@ -308,6 +308,54 @@ public void setMaxMind(int maxMind) { maxAttributes.setMind(maxMind); } + public int getConstitution() { + return attributes.getHealthRegen(); + } + + public int getMaxConstitution() { + return maxAttributes.getHealthRegen(); + } + + public void setConstitution(int constitution) { + attributes.setHealthRegen(constitution); + } + + public void setMaxConstitution(int maxConstitution) { + maxAttributes.setHealthRegen(maxConstitution); + } + + public int getStamina() { + return attributes.getActionRegen(); + } + + public int getMaxStamina() { + return maxAttributes.getActionRegen(); + } + + public void setStamina(int stamina) { + attributes.setActionRegen(stamina); + } + + public void setMaxStamina(int maxStamina) { + maxAttributes.setActionRegen(maxStamina); + } + + public int getWillpower() { + return attributes.getMindRegen(); + } + + public int getMaxWillpower() { + return maxAttributes.getMindRegen(); + } + + public void setWillpower(int willpower) { + attributes.setMindRegen(willpower); + } + + public void setMaxWillpower(int maxWillpower) { + maxAttributes.setMindRegen(maxWillpower); + } + public void putBuff(CRC buffCrc, Buff buff) { synchronized (buffs) { assert !buffs.containsKey(buffCrc) : "Cannot add a buff twice!"; diff --git a/src/utility/java/com/projectswg/utility/ClientdataConvertAll.java b/src/utility/java/com/projectswg/utility/ClientdataConvertAll.java index b032ee741..732cd99c2 100644 --- a/src/utility/java/com/projectswg/utility/ClientdataConvertAll.java +++ b/src/utility/java/com/projectswg/utility/ClientdataConvertAll.java @@ -29,6 +29,9 @@ public static void main(String [] args) throws IOException { Converters.QUESTTASK.load(); Converters.SCHEMATIC_GROUP.load(); Converters.FACTION_RANK.load(); + Converters.CREATION_ATTRIBUTE_LIMITS.load(); + Converters.CREATION_PROFESSION_MODS.load(); + Converters.CREATION_RACIAL_MODS.load(); Converters.XP_LIMITS.load(); } diff --git a/src/utility/java/com/projectswg/utility/clientdata/Converters.java b/src/utility/java/com/projectswg/utility/clientdata/Converters.java index c7b889cc1..2ee19152e 100644 --- a/src/utility/java/com/projectswg/utility/clientdata/Converters.java +++ b/src/utility/java/com/projectswg/utility/clientdata/Converters.java @@ -23,6 +23,9 @@ public enum Converters { QUESTTASK (ConvertQuestTasks::new), SCHEMATIC_GROUP (() -> new ConvertDatatable("datatables/crafting/schematic_group.iff", "serverdata/crafting/schematic_group.sdb", true)), FACTION_RANK (() -> new ConvertDatatable("datatables/faction/rank.iff", "serverdata/faction/rank.sdb", true)), + CREATION_ATTRIBUTE_LIMITS (() -> new ConvertDatatable("datatables/creation/attribute_limits.iff", "serverdata/creation/attribute_limits.sdb", true)), + CREATION_PROFESSION_MODS (() -> new ConvertDatatable("datatables/creation/profession_mods.iff", "serverdata/creation/profession_mods.sdb", true)), + CREATION_RACIAL_MODS (() -> new ConvertDatatable("datatables/creation/racial_mods.iff", "serverdata/creation/racial_mods.sdb", true)), XP_LIMITS (() -> new ConvertDatatable("datatables/skill/xp_limits.iff", "serverdata/skill/xp_limits.sdb", true)), STRINGS (ConvertStrings::new), TERRAINS (ConvertTerrain::new);