Draft: Ajout d'un bestiaire #109

Open
kazhnuz wants to merge 6 commits from bestiaire into main
78 changed files with 2256 additions and 0 deletions

1
_data/bestiaires.json Normal file
View file

@ -0,0 +1 @@
[{"folder":"animaux","list":[{"type":"bête","nom":"Belier","categorie":"biologique","level":0,"rang":"E"},{"type":"bête","nom":"Chien","categorie":"biologique","level":0,"rang":"E"},{"type":"bête","nom":"Petit Chien","categorie":"biologique","level":0,"rang":"E"},{"type":"bête","nom":"Loup","categorie":"biologique","level":2,"rang":"C"},{"type":"bête","nom":"Chef-Loup","categorie":"biologique","level":3,"rang":"B"},{"type":"bête","nom":"Loup Géant","categorie":"biologique","level":4,"rang":"A"},{"type":"bête","nom":"Cheval","categorie":"biologique","level":2,"rang":"C"},{"type":"bête","nom":"Chèvre","categorie":"biologique","level":0,"rang":"E"},{"type":"bête","nom":"Chat","categorie":"biologique","level":0,"rang":"E"},{"type":"bête","nom":"Lynx","categorie":"biologique","level":1,"rang":"D"},{"type":"bête","nom":"Fauve","categorie":"biologique","level":3,"rang":"B"},{"type":"bête","nom":"Lion géant","categorie":"biologique","level":4,"rang":"A"},{"type":"bête","nom":"Ours","categorie":"biologique","level":3,"rang":"B"},{"type":"bête","nom":"Rat","categorie":"biologique","level":0,"rang":"E"},{"type":"aerien","nom":"Chauve souris","categorie":"biologique","level":1,"rang":"D"},{"type":"bête","nom":"Gros rat","categorie":"biologique","level":1,"rang":"D"},{"type":"bête","nom":"Nuée de rats","categorie":"biologique","level":1,"rang":"D"},{"type":"aerien","nom":"Nuée de chauve souris","categorie":"biologique","level":1,"rang":"D"},{"type":"bête","nom":"Rat pestiféré","categorie":"biologique","level":1,"rang":"D"},{"type":"bête","nom":"Rat géant","categorie":"biologique","level":2,"rang":"C"},{"type":"aerien","nom":"Chauve souris vampire","categorie":"biologique","level":2,"rang":"C"},{"type":"bête","nom":"Rat géant pestiféré","categorie":"biologique","level":3,"rang":"B"},{"type":"bête","nom":"Nuée de rats pestiféré","categorie":"biologique","level":3,"rang":"B"},{"type":"aerien","nom":"Nuée de chauve souris vampire","categorie":"biologique","level":3,"rang":"B"},{"type":"bête","nom":"Renard","categorie":"biologique","level":1,"rang":"D"},{"type":"bête","nom":"Vache","categorie":"biologique","level":2,"rang":"C"}],"description":"Des animaux génériques et communs (ou moins communs)","nom":"Animaux"},{"folder":"demons","list":[{"type":"bête","nom":"Chihuahua infernal","categorie":"biologique","level":2,"rang":"C"},{"type":"bête","nom":"Chien des enfers","categorie":"biologique","level":2,"rang":"C"},{"type":"bête","nom":"Loup des enfers","categorie":"biologique","level":3,"rang":"B"},{"type":"bête","nom":"Chef-Loup des enfers","categorie":"biologique","level":4,"rang":"A"},{"type":"bête","nom":"Loup du pandémonium","categorie":"biologique","level":5,"rang":"S"}],"description":"Créatures des enfers et satanistes","nom":"Démons et enfer"}]

1
_data/creatures.json Normal file

File diff suppressed because one or more lines are too long

1
bestiaire/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
build/*.json

View file

@ -0,0 +1,57 @@
local BeastFile = Object:extend()
local DataList = require "classes.datalist"
local parseFile = require "libs.filereader"
function BeastFile:new(folder, name, forceLevel)
self.filepath = folder .. "/" .. name
print("Loading " .. self.filepath)
self.datas = DataList(forceLevel)
self:readLines()
end
function BeastFile:readLines()
self:readAllLines(self.filepath)
end
function BeastFile:readAllLines(path)
parseFile(path, function (line) self:addLine(line) end)
end
function BeastFile:addLine(line)
if (utils.startswith(line, "mixin;") or utils.startswith(line, "mixins;")) then
local mixin = utils.split(line, ";", true)[2]
self:loadMixin(mixin)
elseif (utils.startswith(line, "type;") or utils.startswith(line, "types;")) then
local mixin = utils.split(line, ";", true)[2]
self:loadMixin("types/" .. mixin)
else
self.datas:addLine(line)
end
end
function BeastFile:loadMixin(mixin)
local testpath = "data/" .. utils.trim(mixin) .. ".beast"
if (testpath ~= nil) then
self:readAllLines(testpath)
end
end
function BeastFile:forceName(name)
self.datas:forceName(name)
end
function BeastFile:prepareJson(simplercreatures, creatures, parent)
assert(simplercreatures ~= nil)
assert(creatures ~= nil)
self.datas:prepareJson(simplercreatures, creatures, parent)
end
function BeastFile:getRawData()
local content = {}
self.datas:prepareJson({}, content, "Nothing")
return content[1]
end
return BeastFile

View file

@ -0,0 +1,46 @@
local ArmesHolder = Object:extend()
local function applyBoost(level, mode, value)
return math.floor(value * boosts.getBoost(level, mode))
end
function ArmesHolder:new(key, datas)
self.key = key
self.datas = datas
self.list = {}
end
function ArmesHolder:applyCommand(command, args)
if (command == "") then
self:add(args)
elseif (command == "reset") then
self:reset()
elseif (command == "replace") then
self:replace(args)
end
end
function ArmesHolder:reset()
self.list = {}
end
function ArmesHolder:add(datas)
table.insert(self.list, {nom = datas[1], force = tonumber(datas[2]) or "0"})
end
function ArmesHolder:replace(datas)
for index, args in ipairs(self.list) do
if (args.nom == datas[1]) then
self.list[index] = {nom = datas[1], force = tonumber(datas[2] or "0")}
end
end
end
function ArmesHolder:reduce(level, mode)
for key, value in pairs(self.list) do
value.force = applyBoost(level, mode, value.force)
end
return self.list
end
return ArmesHolder

View file

@ -0,0 +1,28 @@
local ArmureHolder = Object:extend()
function ArmureHolder:new(key, datas)
self.key = key
self.datas = datas
self.commands = {}
end
function ArmureHolder:applyCommand(command, args)
self.commands[command] = args
end
function ArmureHolder:reduce(level, mode)
local stat = self:getBase(level, mode) + ((self.commands.lvl or 0) * level) + (self.commands.add or 0) + (self.commands.bonus or 0)
local modulo = commands.structs[self.key].modulo or 1
datas = commands.structs[self.key]
stat = math.floor(stat / modulo) * modulo
stat = math.min(stat, datas.max or 999999)
stat = math.max(stat, datas.min or -99999)
return stat
end
function ArmureHolder:getBase(level, mode)
return math.floor(self.commands.base * boosts.getBoost(level, mode))
end
return ArmureHolder

View file

@ -0,0 +1,31 @@
local BoostHolder = Object:extend()
function BoostHolder:new(list)
self.parent = list
self.table = {}
end
function BoostHolder:add(name, val)
if (self.table[name] == nil) then
self.table[name] = val
else
self.table[name] = self.table[name] + val
end
end
function BoostHolder:getValue(name, val)
if (name == "pv" or name == "pe") then
return val * 3
else
return val * 5
end
end
function BoostHolder:apply()
for key, value in pairs(self.table) do
-- TODO : a changer entièrement
self.parent:addToHolder(key, "lvl", self:getValue(key, value * 2))
end
end
return BoostHolder

View file

@ -0,0 +1,59 @@
local CompetenceHolder = Object:extend()
local Competence = Object:extend()
function Competence:new(name)
self.name = name;
self.base = 0;
self.lvl = 0;
self.bonus = 0;
self.add = 0;
end
function Competence:reduce(level)
local baseValue = self.base + (self.lvl * level) + self.bonus + self.add
return {
name = self.name,
value = math.floor(baseValue / 5) * 5
}
end
function CompetenceHolder:new(key, datas)
self.key = key
self.datas = datas
self.list = {}
end
function CompetenceHolder:applyCommand(command, args)
if (command == "reset") then
self.list = {}
return
end
local competence = self:getCompetence(args[1])
if (command == "") then
competence.base = tonumber(args[2]) or 0
elseif (command == "add") then
competence.add = tonumber(args[2]) or 0
elseif (command == "bonus") then
competence.bonus = tonumber(args[2]) or 0
elseif (command == "lvl") then
competence.lvl = tonumber(args[2]) or 0
end
end
function CompetenceHolder:getCompetence(name)
if self.list[name] == nil then
self.list[name] = Competence(name)
end
return self.list[name]
end
function CompetenceHolder:reduce(level)
local list = {}
for key, value in pairs(self.list) do
table.insert(list, value:reduce(level))
end
return list
end
return CompetenceHolder

View file

@ -0,0 +1,39 @@
local ListHolder = Object:extend()
function ListHolder:new(key, datas)
self.key = key
self.datas = datas
self.list = {}
end
function ListHolder:applyCommand(command, args)
if (command == "") then
self:add(args)
elseif (command == "reset") then
self:reset()
elseif (command == "replace") then
self:replace(args)
end
end
function ListHolder:reset()
self.list = {}
end
function ListHolder:add(datas)
table.insert(self.list, datas)
end
function ListHolder:replace(datas)
for index, args in ipairs(self.list) do
if (args[1] == datas[1]) then
self.list[index] = datas
end
end
end
function ListHolder:reduce(level)
return self.list
end
return ListHolder

View file

@ -0,0 +1,17 @@
local SimpleHolder = Object:extend()
function SimpleHolder:new(key, datas)
self.key = key
self.datas = datas
self.value = nil
end
function SimpleHolder:applyCommand(command, args)
self.value = args
end
function SimpleHolder:reduce(level)
return self.value
end
return SimpleHolder

View file

@ -0,0 +1,23 @@
local StatHolder = Object:extend()
function StatHolder:new(key, datas)
self.key = key
self.datas = datas
self.commands = {}
end
function StatHolder:applyCommand(command, args)
self.commands[command] = args
end
function StatHolder:reduce(level, mode)
local stat = self.commands.base + ((self.commands.lvl or 0) * level) + (self.commands.add or 0) + (self.commands.bonus or 0)
local modulo = commands.structs[self.key].modulo or 1
datas = commands.structs[self.key]
stat = math.floor(stat / modulo) * modulo
stat = math.min(stat, datas.max or 999999)
stat = math.max(stat, datas.min or -99999)
return stat
end
return StatHolder

View file

@ -0,0 +1,20 @@
local VitaHolder = Object:extend()
function VitaHolder:new(key, datas)
self.key = key
self.datas = datas
self.commands = {}
end
function VitaHolder:applyCommand(command, args)
self.commands[command] = args
end
function VitaHolder:reduce(level, mode)
local stat = (self.commands.base + (self.commands.add or 0))
stat = stat * (level+1)
stat = stat + (self.commands.bonus or 0)
return math.floor(stat)
end
return VitaHolder

View file

@ -0,0 +1,180 @@
local RawData = Object:extend()
local DataList = Object:extend()
local ListHolder = require "classes.dataholders.listholder"
local SimpleHolder = require "classes.dataholders.simpleholder"
local StatHolder = require "classes.dataholders.statholder"
local CompetenceHolder = require "classes.dataholders.competenceholder"
local ArmesHolder = require "classes.dataholders.armesholder"
local ArmureHolder = require "classes.dataholders.armureholder"
local VitaHolder = require "classes.dataholders.vitaholder"
local BoostHolder = require "classes.dataholders.boostholder"
local rank = require "levels.ranks"
function RawData.fromLine(line)
line = utils.removeComment(line)
if (#line == 0) then
return nil
end
local command = utils.split(line, "|")
local datas = utils.split(utils.trim(command[1]), ";")
local args = {}
name = utils.trim(datas[1])
for i, v in ipairs(datas) do
if (i > 1) then
local str = utils.trim(v)
if ((str ~= nil and str ~= "") or i < #datas) then
table.insert(args, str)
end
end
end
local level = 0
if (command[2] ~= nil) then
levelString = utils.trim(command[2]);
level = tonumber(levelString) or 0
end
return RawData(name, commands.clean(args, name), level)
end
function RawData:new(name, arguments, level)
self.name = name
self.arguments = arguments
self.level = level
end
function RawData:canBeUsed(level)
return level >= self.level
end
function RawData:getKey()
return utils.split(self.name, ".", true)[1]
end
function RawData:getCommand()
return utils.split(self.name, ".", true)[2] or ""
end
function DataList.getHolder(key, value)
if (value.dataType == "list") then
return ListHolder(key, value)
elseif (value.dataType == "comp") then
return CompetenceHolder(key, value)
elseif (value.dataType == "stat") then
return StatHolder(key, value)
elseif (value.dataType == "armure") then
return ArmureHolder(key, value)
elseif (value.dataType == "armes") then
return ArmesHolder(key, value)
elseif (value.dataType == "vita") then
return VitaHolder(key, value)
end
return SimpleHolder(key, value)
end
function DataList:new(forceLevel)
self.forcedLevel = forceLevel
self.forcedName = nil
self.list = {}
self.holders = {}
self.reducedList = {}
for key, value in pairs(commands.getDefaults()) do
table.insert(self.list, RawData(key, value, 0))
end
for key, struct in pairs(commands.structs) do
self.holders[key] = DataList.getHolder(key, struct)
end
self.boosts = BoostHolder(self)
end
function DataList:addLine(line)
table.insert(self.list, RawData.fromLine(line))
end
function DataList:forceName(name)
self.forcedName = name
end
function DataList:addToHolder(key, command, arguments)
self.holders[key]:applyCommand(command, arguments)
end
function DataList:reduce()
local level = 0
local mode = "creature"
for _, rawdata in ipairs(self.list) do
if (rawdata.name == "level") then
level = rawdata.arguments
end
if (rawdata.name == "mode") then
mode = rawdata.arguments
end
if (rawdata.name == "boost") then
self.boosts:add(rawdata.arguments[1], rawdata.arguments[2])
end
end
if (self.forcedLevel ~= nil) then
level = self.forcedLevel
end
for _, rawdata in ipairs(self.list) do
if (rawdata:canBeUsed(level) and rawdata.name ~= "boost" and rawdata.name ~= "halfboost") then
self:addToHolder(rawdata:getKey(), rawdata:getCommand(), rawdata.arguments)
end
end
self.boosts:apply()
for key, holder in pairs(self.holders) do
self:addToReducedList(key, holder:reduce(level, mode))
end
if (self.forcedLevel ~= nil) then
self.reducedList["level"] = self.forcedLevel
end
if (self.forcedName ~= nil) then
self.reducedList["name"] = self.forcedName
end
if (level > 6) then
print("[WARNING] Les niveaux au dessus de 6 ne sont pas encore implémentés (" .. self.reducedList["name"] .. ":" .. level .. ")")
end
self.reducedList["rang"] = rank[math.min(level + 1, #rank)]
end
function DataList:addToReducedList(key, data)
local to = commands.structs[key].to or key
local toSplited = utils.split(to, ".", true)
if (#toSplited == 1) then
self.reducedList[to] = data
else
local list = self.reducedList
for i, toPart in ipairs(toSplited) do
if (i == #toSplited) then
list[toPart] = data
else
if (list[toPart] == nil) then
list[toPart] = {}
end
list = list[toPart]
end
end
end
end
function DataList:prepareJson(simplercreatures, creatures, parent)
self:reduce()
self.reducedList.parent = parent
table.insert(simplercreatures, {nom = self.reducedList.name, rang = self.reducedList.rang, level = self.reducedList.level, type = self.reducedList.type, categorie = self.reducedList.categorie})
table.insert(creatures, self.reducedList)
end
return DataList

View file

@ -0,0 +1,55 @@
local FolderLoader = Object:extend()
local BeastFile = require "classes.beastfile"
local GroupFile = require "classes.groupfile"
function FolderLoader.getAllDatas(value, bestiaires, creatures)
local folderLoader = FolderLoader(value)
folderLoader:getDatas(bestiaires, creatures)
end
function FolderLoader:new(value)
self.folder = "data/" .. value.folder
self.data = {}
self.data.nom = value.nom
self.data.description = value.description
self.data.folder = value.folder
self.data.list = {}
self.files = {}
for _, filename in ipairs(utils.scandir(self.folder)) do
local file = utils.split(filename, ".", true)
if (file[2] == "beast") then
table.insert(self.files, BeastFile(self.folder, filename))
elseif (file[2] == "group") then
table.insert(self.files, GroupFile(self.folder, filename))
else
print("[WARNING] Unknown extension " .. file[2] .. " for " .. filename)
end
end
end
function FolderLoader:prepareJson(simplercreatures, creatures)
for _, file in ipairs(self.files) do
file:prepareJson(simplercreatures, creatures, self.data.nom)
end
end
function FolderLoader:getDatas(bestiaires, creatures)
local simplercreatures = {}
self:prepareJson(simplercreatures, creatures)
local bestiaire = {
nom = self.data.nom,
description = self.data.description,
folder = self.data.folder,
list = simplercreatures
}
table.insert(bestiaires, bestiaire)
end
return FolderLoader

View file

@ -0,0 +1,64 @@
local GroupFile = Object:extend()
local BeastFile = require "classes.beastfile"
local parseFile = require "libs.filereader"
function GroupFile:new(folder, name, forceLevel)
self.filepath = folder .. "/" .. name
print("Loading " .. self.filepath)
self.datas = {}
self:readLines()
end
function GroupFile:readLines()
self:readAllLines(self.filepath)
end
function GroupFile:readAllLines(path)
parseFile(path, function (line) self:addLine(line) end)
end
function GroupFile:addLine(line)
if (utils.startswith(line, "beast;") or utils.startswith(line, "beasts;")) then
local datas = utils.split(line, ";", true)
self:addBeast(datas[2], datas[3], datas[4], self:getMixins(datas))
end
end
function GroupFile:getMixins(datas)
if (#datas < 4) then
return {}
else
local list = {}
for index, value in ipairs(datas) do
if (index > 4) then
table.insert(list, value)
end
end
return list
end
end
function GroupFile:addBeast(name, level, baseFile, mixins)
local beast = BeastFile("data", baseFile .. ".beast", tonumber(level))
if (#mixins > 0) then
for index, mixin in ipairs(mixins) do
beast:loadMixin(mixin)
end
end
beast:forceName(name)
table.insert(self.datas, beast)
end
function GroupFile:prepareJson(simplercreatures, creatures, parent)
assert(simplercreatures ~= nil)
assert(creatures ~= nil)
--self.datas:prepareJson(simplercreatures, creatures, parent)
for _, beast in ipairs(self.datas) do
beast:prepareJson(simplercreatures, creatures, parent)
end
end
return GroupFile

5
bestiaire/config.lua Normal file
View file

@ -0,0 +1,5 @@
return {
{nom = "Animaux", folder = "animaux", description = "Des animaux génériques et communs (ou moins communs)", descriptionPage = "Cette page comporte les animaux génériques et communs qu'on peut voir tout les jours, plus quelques animaux plus grand que d'habitude. Ces créatures vont être généralement de niveaux plus faible que d'autres que vous pourrez rencontrer plus tard dans le jeu (apres une vache ça reste dangereux hein)"},
{nom = "Démons et enfer", folder = "demons", description = "Créatures des enfers et satanistes", descriptionPage = "Cette page comporte les créatures et base de PNJ lié aux enfers. Cela peut contenir des démons, des satanistes, ou d'autres créatures lié aux enfers. Ces êtres sont souvent lié à l'élément *chaos*."},
}

View file

@ -0,0 +1,26 @@
type;bete
mixins;bases/corps/quadripede
level;0
name;Belier
// 4 boosts de stats
boost;hab;.5
boost;rel;1
boost;con;.5
boost;per;1
boost;pv;1
armurephy.base;3
armurepsy.base;0
armurespe.base;3
competence;Charge;10;
competence.lvl;Charge;3;
competence;Evasion;10;
competence.lvl;Evasion;3;
armes;Corne;3;
skill;Charge (1 tours de cooldown);Peut charger et envoyer deux dés d'attaque au lieu d'un;
skill;Broute; Peut faire une attaque qui fait des dégats mentaux aux végétaux;
skill;Laine;+2 armures spéciale de base (scale avec le niveau, déjà présent dans les armures);

View file

@ -0,0 +1,5 @@
beast;Chien;0;generique/canides
beast;Petit Chien;0;generique/canides;bases/tailles/petit
beast;Loup;2;generique/canides
beast;Chef-Loup;3;generique/canides
beast;Loup Géant;4;generique/canides;bases/tailles/grand

View file

@ -0,0 +1,22 @@
type;bete
mixins;bases/corps/quadripede
mixins;bases/tailles/grand
level;2
name;Cheval
// 4 boosts de stats
boost;hab;.5
boost;rel;.5
boost;con;1
boost;pv;2
armurephy.base;3
armurepsy.base;0
armurespe.base;1
competence;Charge;10;
competence.lvl;Charge;3;
skill;Galop;Peut faire sa vitesse pur sur sa FOR;
skill;Monture;Peut servir de monture, jouera au même tour;
skill;Ruade (2 tours de cooldown);Une attaque qui projette l'ennemi et à 1/4 chance de stun;

View file

@ -0,0 +1,25 @@
type;bete
mixins;bases/corps/quadripede
level;0
name;Chèvre
// 4 boosts de stats
boost;hab;.5
boost;rel;.5
boost;int;1
boost;per;1
boost;pv;1
armurephy.base;3
armurepsy.base;0
armurespe.base;1
competence;Charge;10;
competence.lvl;Charge;3;
competence;Evasion;10;
competence.lvl;Evasion;3;
armes;Corne;3;
skill;Charge (1 tours de cooldown);Peut charger et envoyer deux dés d'attaque au lieu d'un;
skill;Broute; Peut faire une attaque qui fait des dégats mentaux aux végétaux;

View file

@ -0,0 +1,4 @@
beast;Chat;0;generique/felides;bases/tailles/petit
beast;Lynx;1;generique/felides
beast;Fauve;3;generique/felides
beast;Lion géant;4;generique/felides;bases/tailles/grand

View file

@ -0,0 +1,3 @@
mixins;generique/ursides
level;3
name;Ours

View file

@ -0,0 +1,11 @@
beast;Rat;0;generique/rat
beast;Chauve souris;1;generique/rat;types/aerien
beast;Gros rat;1;generique/rat;bases/tailles/petit
beast;Nuée de rats;1;generique/rat;bases/special/nuee
beast;Nuée de chauve souris;1;generique/rat;types/aerien
beast;Rat pestiféré;1;generique/rat;bases/special/pestilent
beast;Rat géant;2;generique/rat
beast;Chauve souris vampire;2;generique/rat;types/aerien;bases/special/vampirisme
beast;Rat géant pestiféré;3;generique/rat;generique/rat;bases/special/pestilent
beast;Nuée de rats pestiféré;3;generique/rat;bases/special/nuee;bases/special/pestilent
beast;Nuée de chauve souris vampire;3;generique/rat;types/aerien;bases/special/nuee;bases/special/vampirisme

View file

@ -0,0 +1,27 @@
type;bete
mixins;bases/corps/quadripede
level;1
name;Renard
// 4 boosts de stats
boost;int;1
boost;hab;1
boost;rel;.5
boost;atk;.5
boost;pv;.5
boost;int;.5
armurephy.base;2
armurepsy.base;0
armurespe.base;1
competence;Chasse;10;
competence.lvl;Chasse;3;
competence;Pistage;10;
competence.lvl;Pistage;3;
armes;Griffe;3;
armes;Croc;4;
skill;Morsure;Une attaque qui utilise les crocs et fait 1 blessure;
skill;Griffure;Fait deux attaques à -30% de chance de toucher;

View file

@ -0,0 +1,24 @@
type;bete
mixins;bases/corps/quadripede
mixins;bases/tailles/grand
level;2
name;Vache
// 4 boosts de stats
boost;atk;.5
boost;rel;.5
boost;con;1
boost;pv;2
armurephy.base;4
armurepsy.base;0
armurespe.base;2
competence;Charge;10;
competence.lvl;Charge;3;
armes;Corne;3;
skill;Charge (1 tours de cooldown);Peut charger et envoyer deux dés d'attaque au lieu d'un;
skill;Monture;Peut servir de monture, jouera au même tour;
skill;Empalement (2 tours de cooldown);Attaque qui provoque 1D4 blessure, mais n'a qu'une chance sur 2 de réussir; | 6

View file

@ -0,0 +1,16 @@
atk.base;60
con.base;50
hab.base;50
int.base;30
sag.base;30
vol.base;50
cha.base;50
dis.base;50
rel.base;60
per.base;50
pv.base;12
pe.base;12

View file

@ -0,0 +1,16 @@
atk.base;65
con.base;65
hab.base;70
int.base;15
sag.base;30
vol.base;30
cha.base;60
dis.base;60
rel.base;40
per.base;70
pv.base;18
pe.base;9

View file

@ -0,0 +1,16 @@
atk.base;60
con.base;55
hab.base;65
int.base;15
sag.base;30
vol.base;30
cha.base;60
dis.base;70
rel.base;20
per.base;70
pv.base;15
pe.base;9

View file

@ -0,0 +1,16 @@
atk.base;60
con.base;30
hab.base;70
int.base;15
sag.base;30
vol.base;30
cha.base;50
dis.base;50
rel.base;40
per.base;65
pv.base;15
pe.base;9

View file

@ -0,0 +1,2 @@
mixins;bases/special/demons
skill;Blessure infernale;besoin de deux soin pour soigner une blessure, les blessures restante après le combat provoque un malus physique sur le long terme;

View file

@ -0,0 +1,5 @@
faiblesse;ordre
resistence;chaos
skill;Force chaotique;Regagne 1D6 PV - 3 par tour en terrain chaotique;
skill;Attaque démoniaque;Attaque avec effet de chaos (L'attaque fait moitié dégats sur le corps et l'esprit.)

View file

@ -0,0 +1 @@
skill;Nuée;PV × 1D8, correspond au nombre de créature. Au max 3 attaque par tour tant qu'il y a assez de créature. Les attaque non de zone font max le nombre de PV de base de la créature. Les soins ne peuvent ramener des membres de la nuée. La nuée perd 10% en hab pour esquiver tant qu'il y a des membres.;

View file

@ -0,0 +1 @@
skill;Pestilence;Ses attaques physique font l'effet poison;

View file

@ -0,0 +1 @@
skill;Vampirisme (1 tour de cooldown);Une attaque au corps à corps qui soigne à l'attaquant 50% des dégats infligés à l'ennemi.;

View file

@ -0,0 +1,8 @@
// Créature grande (ours)
atk.bonus;15
con.bonus;15
hab.bonus;-15
per.bonus;-15
pv.bonus;3;
armurephy.bonus;1;

View file

@ -0,0 +1,10 @@
// Créature minuscule (insecte)
atk.bonus;-30
con.bonus;-30
hab.bonus;30
per.bonus;30
pv.bonus;0;
pv.base;1;
pv.lvl;0;
armurephy.bonus;-1;

View file

@ -0,0 +1,8 @@
// Créature normale
atk.bonus;0
con.bonus;0
hab.bonus;0
per.bonus;0
pv.bonus;0;
armurephy.bonus;0;

View file

@ -0,0 +1,8 @@
// Créature petite (chat à chien)
atk.bonus;-15
con.bonus;-15
hab.bonus;15
per.bonus;15
pv.bonus;-3;
armurephy.bonus;-1;

View file

@ -0,0 +1,8 @@
// Créature très grande (rhino / éléphant)
atk.bonus;25
con.bonus;25
hab.bonus;-25
per.bonus;-25
pv.bonus;6;
armurephy.bonus;2;

View file

@ -0,0 +1,8 @@
// Créature très petite (rat, etc)
atk.bonus;-25
con.bonus;-25
hab.bonus;25
per.bonus;25
pv.bonus;-6;
armurephy.bonus;-1;

View file

@ -0,0 +1,5 @@
beast;Chihuahua infernal;2;generique/canides;bases/tailles/petit;bases/special/demons-betes
beast;Chien des enfers;2;generique/canides
beast;Loup des enfers;3;generique/canides;bases/special/demons-betes
beast;Chef-Loup des enfers;4;generique/canides;bases/special/demons-betes
beast;Loup du pandémonium;5;generique/canides;bases/tailles/grand;bases/special/demons-betes

View file

@ -0,0 +1,27 @@
type;bete
mixins;bases/corps/quadripede
// 4 boosts à rajouter
boost;atk;1.5
boost;pv;1
boost;pe;.5
boost;hab;.5
boost;con;.5
armurephy.base;2
armurepsy.base;0
armurespe.base;1
competence;Chasse;10;
competence.lvl;Chasse;3;
competence;Pistage;10;
competence.lvl;Pistage;3;
armes;Griffe;3;
armes;Croc;4;
skill;Morsure;Une attaque qui utilise les crocs et fait 1 blessure;
skill;Griffure;Fait deux attaques à -30% de chance de toucher;
skill;Bêtes de meute;+5% pour toucher des zones difficiles par créature de meute présente;
skill;Férocité (trois tour de cooldown);Peut doubler les dégats d'une attaque, mais se prendra 50% des dégats en retour | 6

View file

@ -0,0 +1,27 @@
type;bete
mixins;bases/corps/quadripede
// 4 boosts à rajouter
boost;atk;1
boost;hab;1
boost;pv;1
boost;int;.5
boost;dis;.5
armurephy.base;1
armurepsy.base;0
armurespe.base;1
competence;Chasse;10;
competence.lvl;Chasse;2;
competence;Pistage;10;
competence.lvl;Pistage;2;
competence;Grimpette;10;
competence.lvl;Pistage;2;
armes;Griffe;3;
armes;Croc;4;
skill;Morsure;Une attaque qui utilise les crocs et fait 1 blessure;
skill;Griffure;Fait deux attaques à -30% de chance de toucher;

View file

@ -0,0 +1,25 @@
type;bete
mixins;bases/corps/quadripede
mixins;bases/tailles/trespetit
level;0
name;Rat
// 4 boosts de stats
boost;int;1
boost;hab;2
boost;dis;1
armurephy.base;0
armurepsy.base;0
armurespe.base;0
competence;Cachette;10;
competence.lvl;Cachette;3;
competence;Fouille;10;
competence.lvl;Fouille;3;
armes;Griffe;1;
armes;Croc;2;
skill;Morsure;Une attaque qui utilise les crocs et fait 1 blessure;
skill;Attaque accrochée;S'accroche et fait 1 dégats / tour;

View file

@ -0,0 +1,23 @@
type;bete
mixins;bases/corps/quadripede
mixins;bases/tailles/grand
// 4 boost à passer par niveau
boost;atk;1
boost;con;1
boost;pv;2
armurephy.base;4
armurepsy.base;0
armurespe.base;2
competence;Chasse;10;
competence.lvl;Chasse;3;
competence;Pistage;10;
competence.lvl;Pistage;3;
armes;Griffe;4;
armes;Croc;5;
skill;Morsure;Une attaque qui utilise les crocs et fait 2 blessure;
skill;Griffure;Fait deux attaques à -30% de chance de toucher;

View file

@ -0,0 +1,5 @@
nomType;aerien
categorie;biologique
faiblesse;air
resistence;terre
skill;Vol;Peut voler, +30% pour esquiver les attaques terrestres

View file

@ -0,0 +1,5 @@
nomType;aquatique
categorie;biologique
faiblesse;foudre
resistance;eau
skill;Aquatique;N'a pas de malus dans l'eau

View file

@ -0,0 +1,3 @@
nomType;bête
categorie;biologique
faiblesse;metal

View file

@ -0,0 +1,5 @@
nomType;feufolet
categorie;non-biologique
faiblesse;eau
faiblesse;terre
resistance;glace

View file

@ -0,0 +1,6 @@
nomType;gelatineux
categorie;non-biologique
faiblesse;metal
faiblesse;son
resistance;force
resistance;eau

View file

@ -0,0 +1,4 @@
nomType;créature de glace
categorie;non-biologique
faiblesse;feu
resistance;glace

View file

@ -0,0 +1,2 @@
nomType;humanoïde
categorie;biologique

View file

@ -0,0 +1,3 @@
nomType;insecte
categorie;biologique
faiblesse;feu

View file

@ -0,0 +1,5 @@
nomType;machine
categorie;non-biologique
immunite;poison
faiblesse;foudre
faiblesse;eau

View file

@ -0,0 +1,4 @@
nomType;mineraloïde
categorie;non-biologique
resistance;poison
resistance;feu

View file

@ -0,0 +1,3 @@
nomType;reptile
categorie;biologique
faiblesse;glace

View file

@ -0,0 +1,4 @@
nomType;vegetal
categorie;biologique
faiblesse;feu
resistance;vegetal

View file

@ -0,0 +1,5 @@
nomType;volute
categorie;non-biologique
faiblesse;air
resistance;terre
resistance;metal

View file

@ -0,0 +1,15 @@
local datas = {}
datas.hp = {1, 1, 2, 3, 4, 5, 6}
datas.competences = {10, 30, 30, 50, 50, 70}
datas.stats = {
[0] = {base = 40, malus = {20, 30, 30}, bonus = {50, 50, 60}},
[1] = {base = 50, malus = {20, 30, 40}, bonus = {60, 70, 80}},
[2] = {base = 50, malus = {30, 30, 40}, bonus = {70, 80, 80}},
[3] = {base = 50, malus = {30, 30, 40}, bonus = {80, 80, 100}}, -- Potentiel
[4] = {base = 50, malus = {30, 40, 40}, bonus = {80, 80, 120}},
[5] = {base = 50, malus = {30, 40, 40}, bonus = {80, 100, 140}}, -- Potentiel+
[6] = {base = 60, malus = {30, 40, 50}, bonus = {80, 120, 150}},
[7] = {base = 60, malus = {30, 40, 50}, bonus = {80, 130, 180}}, -- Supérieur au max des joueurs
[8] = {base = 60, malus = {40, 40, 50}, bonus = {120, 150, 200}},
}

15
bestiaire/levels/pnj.lua Normal file
View file

@ -0,0 +1,15 @@
local datas = {}
datas.hp = {1, 1, 2, 3, 4, 5, 6}
datas.competences = {10, 30, 30, 50, 50, 70}
datas.stats = {
[0] = {base = 40, malus = {20, 30, 30}, bonus = {50, 50, 60}},
[1] = {base = 50, malus = {20, 30, 40}, bonus = {60, 70, 80}},
[2] = {base = 50, malus = {30, 30, 40}, bonus = {70, 80, 80}},
[3] = {base = 50, malus = {30, 30, 40}, bonus = {80, 80, 100}}, -- Potentiel
[4] = {base = 50, malus = {30, 40, 40}, bonus = {80, 80, 120}},
[5] = {base = 50, malus = {30, 40, 40}, bonus = {80, 100, 140}}, -- Potentiel+
[6] = {base = 60, malus = {30, 40, 50}, bonus = {80, 120, 150}},
[7] = {base = 60, malus = {30, 40, 50}, bonus = {80, 130, 180}}, -- Supérieur au max des joueurs
[8] = {base = 60, malus = {40, 40, 50}, bonus = {120, 150, 200}},
}

View file

@ -0,0 +1 @@
return {"E", "D", "C", "B", "A", "S", "X", "", "", "--"}

39
bestiaire/libs/boosts.lua Normal file
View file

@ -0,0 +1,39 @@
local boost = {}
local BOOST_ARM_CREATURE = {
{lvl = 0, value = 1},
{lvl = 2, value = 1.5},
{lvl = 3, value = 2},
{lvl = 5, value = 3},
{lvl = 6, value = 3.5},
{lvl = 7, value = 4}
}
local BOOST_ARM_PNJ = {
{lvl = 0, value = 1},
{lvl = 2, value = 1.5},
{lvl = 4, value = 2},
{lvl = 6, value = 3}
}
local function getBoost(level, table)
local bestBoost = {lvl = -1, value = 1}
for _, boost in ipairs(table) do
if (level >= boost.lvl and boost.lvl > bestBoost.lvl) then
bestBoost = boost
end
end
return bestBoost.value
end
function boost.getBoost(level, mode)
if (mode == "pnj") then
return getBoost(level, BOOST_ARM_PNJ)
else
return getBoost(level, BOOST_ARM_CREATURE)
end
end
return boost

View file

@ -0,0 +1,68 @@
--
-- classic
--
-- Copyright (c) 2014, rxi
--
-- This module is free software; you can redistribute it and/or modify it under
-- the terms of the MIT license. See LICENSE for details.
--
local Object = {}
Object.__index = Object
function Object:new()
end
function Object:extend()
local cls = {}
for k, v in pairs(self) do
if k:find("__") == 1 then
cls[k] = v
end
end
cls.__index = cls
cls.super = self
setmetatable(cls, self)
return cls
end
function Object:implement(...)
for _, cls in pairs({...}) do
for k, v in pairs(cls) do
if self[k] == nil and type(v) == "function" then
self[k] = v
end
end
end
end
function Object:is(T)
local mt = getmetatable(self)
while mt do
if mt == T then
return true
end
mt = getmetatable(mt)
end
return false
end
function Object:__tostring()
return "Object"
end
function Object:__call(...)
local obj = setmetatable({}, self)
obj:new(...)
return obj
end
return Object

View file

@ -0,0 +1,71 @@
local struct = require "struct"
local commands = {}
local defaults = {}
local functions = {}
print("Compilation des commandes")
local function addCommands(command, parent, default)
commands[command] = parent
if (default ~= nil) then
defaults[command] = default
end
end
local function addStatCommands(name, value)
addCommands(name .. ".base", name, value.default)
addCommands(name .. ".lvl", name, value.lvl or 0)
addCommands(name .. ".add", name, 0)
addCommands(name .. ".bonus", name, 0)
end
local function addCompCommands(name, value)
addCommands(name, name)
addCommands(name .. ".reset", name)
addCommands(name .. ".lvl", name)
addCommands(name .. ".add", name)
addCommands(name .. ".bonus", name)
end
local function addListCommands(name, value)
addCommands(name, name)
addCommands(name .. ".replace", name)
addCommands(name .. ".reset", name)
end
for key, value in pairs(struct) do
if (value.dataType == "stat" or value.dataType == "armure" or value.dataType == "vita") then
addStatCommands(key, value)
elseif (value.dataType == "list") then
addListCommands(key, value)
elseif (value.dataType == "comp" or value.dataType == "armes") then
addCompCommands(key, value)
else
addCommands(key, key, value.default)
end
end
function functions.getDefaults()
return defaults
end
function functions.clean(args, command)
local baseCommand = commands[command]
if (baseCommand == nil) then
error("Command " .. command .. " doesn't exists")
end
local commandData = struct[baseCommand]
if (commandData.args == nil or commandData.args == 1) then
local arg = args[1]
if (commandData.contentType == "number") then
arg = tonumber(arg)
end
return arg
end
return args
end
functions.structs = struct
return functions

View file

@ -0,0 +1,34 @@
-- http://lua-users.org/wiki/FileInputOutput
local utils = require "libs.utils"
-- see if the file exists
local function file_exists(file)
local f = io.open(file, "rb")
if f then f:close() end
return f ~= nil
end
-- get all lines from a file, returns an empty
-- list/table if the file does not exist
local function lines_from(file)
if not file_exists(file) then error(file) end
local lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
local function parseFile(file, func)
local lines = lines_from(file)
for k,v in pairs(lines) do
local line = utils.trim(v)
line = utils.trim(utils.split(line, "//", true)[1])
if (line ~= "") then
func(line)
end
end
end
return parseFile;

4
bestiaire/libs/init.lua Normal file
View file

@ -0,0 +1,4 @@
utils = require "libs.utils"
Object = require "libs.classic"
commands = require "libs.commands"
boosts = require "libs.boosts"

388
bestiaire/libs/json.lua Normal file
View file

@ -0,0 +1,388 @@
--
-- json.lua
--
-- Copyright (c) 2020 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
local json = { _version = "0.1.2" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
[ "\\" ] = "\\",
[ "\"" ] = "\"",
[ "\b" ] = "b",
[ "\f" ] = "f",
[ "\n" ] = "n",
[ "\r" ] = "r",
[ "\t" ] = "t",
}
local escape_char_map_inv = { [ "/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return ( encode(val) )
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end
local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(1, 4), 16 )
local n2 = tonumber( s:sub(7, 10), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local res = ""
local j = i + 1
local k = j
while j <= #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
or str:match("^%x%x%x%x", j + 1)
or decode_error(str, j - 1, "invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
j = j + 1
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
return json

127
bestiaire/libs/split.lua Normal file
View file

@ -0,0 +1,127 @@
------------------------------------------------------------------
--
-- Author: Alexey Melnichuk <alexeymelnichuck@gmail.com>
--
-- Copyright (C) 2016 Alexey Melnichuk <alexeymelnichuck@gmail.com>
--
-- Licensed according to the included 'LICENSE' document
--
-- This file is part of lua-split library.
--
------------------------------------------------------------------
---
-- @usage
-- split = require "split"
-- lines = split(str, '\r?\n')
-- key, val = split.first(str, '=', true)
-- a,b,c,d = split.unpack(str, ':', true)
local unpack = unpack or table.unpack
local function is_match_empty(pat, plain)
return not not string.find('', pat, nil, plain)
end
local function split(str, sep, plain)
local b, res = 0, {}
sep = sep or '%s+'
assert(type(sep) == 'string')
assert(type(str) == 'string')
if #sep == 0 then
for i = 1, #str do
res[#res + 1] = string.sub(str, i, i)
end
return res
end
assert(not is_match_empty(sep, plain), 'delimiter can not match empty string')
while b <= #str do
local e, e2 = string.find(str, sep, b, plain)
if e then
res[#res + 1] = string.sub(str, b, e-1)
b = e2 + 1
if b > #str then res[#res + 1] = "" end
else
res[#res + 1] = string.sub(str, b)
break
end
end
return res
end
local function split_iter(str, sep, plain)
sep = sep or '%s+'
assert(type(sep) == 'string')
assert(type(str) == 'string')
if #sep == 0 then
local i = 0
return function()
i = i + 1
if i > #str then return end
return (string.sub(str, i, i))
end
end
assert(not is_match_empty(sep, plain), 'delimiter can not match empty string')
local b, eol = 0
return function()
if b > #str then
if eol then
eol = nil
return ""
end
return
end
local e, e2 = string.find(str, sep, b, plain)
if e then
local s = string.sub(str, b, e-1)
b = e2 + 1
if b > #str then eol = true end
return s
end
local s = string.sub(str, b)
b = #str + 1
return s
end
end
local function usplit(...) return unpack(split(...)) end
local function split_first(str, sep, plain)
sep = sep or '%s+'
assert(type(sep) == 'string')
assert(type(str) == 'string')
if #sep == 0 then
return string.sub(str, 1, 1), string.sub(str, 2)
end
assert(not is_match_empty(sep, plain), 'delimiter can not match empty string')
local e, e2 = string.find(str, sep, nil, plain)
if e then
return string.sub(str, 1, e - 1), string.sub(str, e2 + 1)
end
return str
end
return setmetatable({
split = split;
unpack = usplit;
first = split_first;
each = split_iter;
},{
__call = function(_, ...)
return split(...)
end
})

69
bestiaire/libs/utils.lua Normal file
View file

@ -0,0 +1,69 @@
local utils = {}
utils.split = require "libs.split"
function utils.trim(s)
return s:match "^%s*(.-)%s*$"
end
function utils.startswith(string, start)
return string:sub(1, #start) == start
end
function utils.endswith(string, ending)
return ending == "" or string:sub(-#ending) == ending
end
function utils.removeComment(line)
return utils.trim(utils.split(utils.trim(line), '/', true)[1])
end
function utils.scandir(directory)
local i, t, popen = 0, {}, io.popen
local pfile = popen('ls -a "'..directory..'"')
for filename in pfile:lines() do
if (filename ~= "." and filename ~= "..") then
i = i + 1
t[i] = filename
end
end
pfile:close()
return t
end
function utils.contains(list, value)
if list == nil then
return false
end
for _, listValue in pairs(list) do
if (listValue == value) then
return true
end
end
return false
end
function utils.size(tableToTest)
if (tableToTest == nil) then
return 0
end
return #tableToTest
end
function utils.slitWithoutWhiteSpace(str, sep, plain)
local strs = utils.split(str, sep, plain)
local strsWithoutWhitespace = {}
for key, value in pairs(strs) do
table.insert(strsWithoutWhitespace, utils.trim(value))
end
return strsWithoutWhitespace
end
function utils.fileExists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
return utils

29
bestiaire/main.lua Normal file
View file

@ -0,0 +1,29 @@
require "libs"
local config = require "config"
local FolderLoader = require "classes.folderloader"
local json = require "libs.json"
print("Début de génération des fichiers .json")
clock = os.clock()
local bestiaires = {}
local creatures = {}
for _, value in ipairs(config) do
print("Charagement de la catégorie " .. value.nom)
FolderLoader.getAllDatas(value, bestiaires, creatures)
end
local file = io.open("../_data/bestiaires.json", "w")
if (file ~= nil) then
file:write(json.encode(bestiaires))
end
local file2 = io.open("../_data/creatures.json", "w")
if (file2 ~= nil) then
file2:write(json.encode(creatures))
end
clock = os.clock() - clock
print("Génération du fichier .json en " .. clock .. " seconds")

31
bestiaire/struct.lua Normal file
View file

@ -0,0 +1,31 @@
return {
name={contentType = "string", preParse = true, to="name"},
mode={contentType = "string", preParse = true, to="mode", default = "creature"},
nomType={contentType = "string", to="type"},
categorie={contentType = "string", to="categorie"},
faiblesse={contentType = "list", args=1},
resistence={contentType = "list", args=1},
immunite={contentType = "list", args=1},
level={contentType = "number", default = 0, preParse = true},
pression={contentType = "number", default = 5},
boost={dataType = "boost", args=2},
atk= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.for"},
con= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.con"},
hab= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.hab"},
int= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.int"},
sag= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.sag"},
vol= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.vol"},
cha= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.cha"},
dis= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.dis"},
rel= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.rel"},
per= {dataType= "stat", modulo= 5, default= 50, max=255, min=10, to="stats.per"},
pv= {dataType= "vita", modulo= 1, default= 12, max=9999999, min=1, to="vita.pv", lvl=1},
pe= {dataType= "vita", modulo= 1, default= 12, max=9999999, min=1, to="vita.pe", lvl=1},
eclat= {dataType= "stat", modulo= 1, default= 10, max=200, min=1, to="vita.eclat"},
armurephy= {dataType= "armure", modulo= 1, default= 0, max=9999999, min=0, to="armure.phy"},
armurepsy= {dataType= "armure", modulo= 1, default= 0, max=9999999, min=0, to="armure.psy"},
armurespe= {dataType= "armure", modulo= 1, default= 0, max=9999999, min=0, to="armure.spe"},
armes= {dataType= "armes", args=2},
competence= {dataType= "comp", args=3}, -- on va le gérer différemment comme du code lol sinon c'est trop relou
skill= {dataType= "list", args=2},
}

32
bestiaire/view.lua Normal file
View file

@ -0,0 +1,32 @@
require "libs"
local config = require "config"
local BeastFile = require "classes.beastfile"
local beast = BeastFile("data", arg[1] .. ".beast", tonumber(arg[2]))
local creature = beast:getRawData()
print(creature.name, "Lvl:" .. creature.level, "Pression:" .. creature.pression, creature["type"], creature.categorie)
print(" ", "------")
print("FOR:" .. creature.stats["for"], "INT:" .. creature.stats.int, "CHA:" .. creature.stats.cha)
print("CON:" .. creature.stats.con, "SAG:" .. creature.stats.sag, "DIS:" .. creature.stats.dis)
print("HAB:" .. creature.stats.hab, "VOL:" .. creature.stats.vol, "REL:" .. creature.stats.rel)
print(" ", "PER:" .. creature.stats.per)
print(" ", "------")
print("PV:" .. creature.vita.pv, "PE:" .. creature.vita.pe, "Eclat:" .. creature.vita.eclat)
print("Armure", "Phy:" .. creature.armure.phy, "Psy:" .. creature.armure.psy, "Spe:" .. creature.armure.spe)
print(" ", "------")
print("Armes:")
for key, value in ipairs(creature.armes) do
print(value.nom, value.force)
end
print(" ", "------")
print("Competences:")
for key, value in ipairs(creature.competence) do
print(value.name, value.value)
end
print(" ", "------")
print("Skills:")
for key, value in ipairs(creature.skill) do
print(value[1], value[2])
end

View file

@ -0,0 +1,34 @@
---
layout: layouts/base.njk
parent: Bestiaire
---
# Toutes les créatures
## Liste des mobs
<div id="dataTable">
<table class="dataTables">
<thead>
<tr>
<th>Rang</th>
<th>Nom</th>
<th>Type</th>
<th>Catégorie</th>
</tr>
</thead>
<tbody>
{%- for creature in creatures -%}
<tr>
<td><span aria-hidden="true" style="opacity:0;position:absolute;">({{ creature.level }})</span> {{ creature.rang }} </td>
<td> <a href="/mobs/bestiaire/creatures/{{ creature.name | slugify }}">{{ creature.name }}</a> </td>
<td>{{ creature.type }} </td>
<td>{{ creature.categorie }} </td>
</tr>
{%- endfor -%}
<tbody>
</table>
</div>

View file

@ -0,0 +1,95 @@
---
pagination:
data: creatures
size: 1
alias: creature
permalink: "mobs/bestiaire/creatures/{{ creature.name | slugify }}/"
layout: layouts/base.njk
parent: "{{ creature.parent }}"
---
# {{ creature.name }}
Créature de type {{ creature.type }}, dans la catégorie *{{ creature.categorie }}*, de rang {{ creature.rang }} et dans le groupe « {{ creature.parent }} ».
| Pression | Faiblesses | Résistences | Immunités |
|:-:|:-:|:-:|:-:|
| {{creature.pression}} | {{creature.faiblesses}} | {{ creature.resistences }} | {{ creatures.immunites }} |
## Statistiques
| | | |
|:-:|:-:|:-:|
| FOR: {{ creature.stats.for }} | INT: {{ creature.stats.int }} | CHA: {{ creature.stats.cha }} |
| CON: {{ creature.stats.con }} | SAG: {{ creature.stats.sag }} | DIS: {{ creature.stats.dis }} |
| HAB: {{ creature.stats.hab }} | VOL: {{ creature.stats.vol }} | REL: {{ creature.stats.rel }} |
| | PER: {{ creature.stats.per }} | |
## Vitalité
| | | |
|:-:|:-:|:-:|
| PV: {{ creature.vita.pv }} | PE: {{ creature.vita.pe }} | Éclat: {{ creature.vita.eclat }} |
| Armure phy: {{ creature.armure.phy }} | Armure spe: {{ creature.armure.spe }} | Armure psy: {{ creature.armure.psy }} |
## Compétences et pouvoirs
<div style="display:flex;">
<div style="width:40%;padding-right:0.5rem;">
<table class="pokedex">
<thead>
<tr>
<th>Arme</th>
<th>Valeur</th>
</tr>
</thead>
<tbody>
{%- for arme in creature.armes -%}
<tr>
<td>{{ arme.nom }}</td>
<td>{{ arme.force }} </td>
</tr>
{%- endfor -%}
<tbody>
</table>
<p></p>
<table class="pokedex">
<thead>
<tr>
<th>Compétence</th>
<th>Valeur</th>
</tr>
</thead>
<tbody>
{%- for competence in creature.competence -%}
<tr>
<td>{{ competence.name }}</td>
<td>{{ competence.value }} </td>
</tr>
{%- endfor -%}
<tbody>
</table>
</div>
<div style="width:60%;padding-left:0.5rem;">
<table class="pokedex">
<thead>
<tr>
<th>Pouvoirs</th>
</tr>
</thead>
<tbody>
{%- for competence in creature.skill -%}
<tr>
<td><strong>{{ competence[0] }}</strong><br />{{ competence[1] }}</td>
</tr>
{%- endfor -%}
<tbody>
</table>
</div>
</div>

View file

@ -0,0 +1,21 @@
---
layout: layouts/base.njk
eleventyNavigation:
key: Bestiaire
parent: Créatures et PNJs
order: 0
title: Bestiaire
---
# Bestiaire
Le bestiaire d'Erratum contient des créatures diverses et variées permettant d'affronter des ennemis ou d'interagir avec des créatures différentes suivants les parties, les lieux, etc. Il est à noter que ce bestiaire n'à pas pour but d'être exhaustif, et que d'autres créatures peuvent être inventées à foisons.
## Bestiaires disponibles
<ul>
<li><a href="/mobs/bestiaire/all">Tout</a> L'ensemble des créatures et PNJ du bestiaire</li>
{% for bestiaire in bestiaires %}
<li><a href="/mobs/bestiaire/{{ bestiaire.folder }}">{{ bestiaire.nom }}</a> {{bestiaire.description}}</li>
{% endfor %}
</ul>

View file

@ -0,0 +1,42 @@
---
pagination:
data: bestiaires
size: 1
alias: bestiaire
permalink: "mobs/bestiaire/{{ bestiaire.folder }}/"
layout: layouts/base.njk
parent: Bestiaire
title: {{ bestiaire.nom }}
---
# {{ bestiaire.nom }}
{{ bestiaire.description }}
## Liste des mobs
<div id="dataTable">
<table class="dataTables">
<thead>
<tr>
<th>Rang</th>
<th>Nom</th>
<th>Type</th>
<th>Catégorie</th>
</tr>
</thead>
<tbody>
{%- for creature in bestiaire.list -%}
<tr>
<td><span aria-hidden="true" style="opacity:0;position:absolute;">({{ creature.level }})</span> {{ creature.rang }} </td>
<td> <a href="/mobs/bestiaire/creatures/{{ creature.nom | slugify }}">{{ creature.nom }}</a> </td>
<td>{{ creature.type }} </td>
<td>{{ creature.categorie }} </td>
</tr>
{%- endfor -%}
<tbody>
</table>
</div>

2
generate.sh Executable file
View file

@ -0,0 +1,2 @@
cd bestiaire
lua main.lua

80
simulateurs/main.lua Normal file
View file

@ -0,0 +1,80 @@
local function getDiceResult(stat, dice)
local estCritique = false
local isReussite = (dice <= stat)
local niveauReussite = math.floor(stat / 10 ) - math.floor( dice / 10)
if (dice <= 5) then
isReussite = true
estCritique = true
niveauReussite = niveauReussite * 2
if (niveauReussite < 0) then
niveauReussite = niveauReussite * -1
end
end
if (dice > 95) then
isReussite = false
estCritique = true
niveauReussite = niveauReussite * 2
if (niveauReussite > 0) then
niveauReussite = niveauReussite * -1
end
end
local unite = dice % 10
return isReussite, niveauReussite, unite
end
local function confrontation(stat1, stat2)
local resultats = {}
local egalites = 0
for i = 1, 100 do
local isReussite1, niveauReussite1, unite1 = getDiceResult(stat1, i)
for j = 1, 100 do
local resultat = {}
resultat.reussite = false
local isReussite2, niveauReussite2, unite2 = getDiceResult(stat2, j)
if (niveauReussite1 == niveauReussite2 and unite1 == unite2) then
egalites = egalites + 1
else
if (niveauReussite1 > niveauReussite2) then
resultat.reussite = true
elseif (niveauReussite1 < niveauReussite2) then
resultat.reussite = false
elseif (unite1 <= unite2) then
resultat.reussite = true
end
resultat.delta = niveauReussite1 - niveauReussite2
table.insert(resultats, resultat)
end
end
end
local total = 0
local totalSansNegatif = 0
local nombreReussite = 0
for _, resultat in ipairs(resultats) do
if (resultat.reussite) then
nombreReussite = nombreReussite + 1
end
total = total + resultat.delta
totalSansNegatif = totalSansNegatif + math.max(0, resultat.delta)
end
local stringPourcentageReussite = string.format( "%.2f%%", (nombreReussite / #resultats) * 100 )
local stringMoyenne = string.format( "%.2f", (total / #resultats) )
local stringMoyenneSansNegatif = string.format( "%.2f", (totalSansNegatif / #resultats) )
local stringEgalites = string.format( "%.2f%%", (egalites / 10000) * 100 )
return stringPourcentageReussite, stringMoyenne, stringMoyenneSansNegatif, stringEgalites
end
local stringPourcentageReussite, stringMoyenne, stringMoyenneSansNegatif, stringEgalites = confrontation(tonumber(arg[1]), tonumber(arg[2]))
print(stringPourcentageReussite, stringMoyenne, stringMoyenneSansNegatif)
print("Egalités :", stringEgalites)