Compare commits

..

6 commits

Author SHA1 Message Date
Kazhnuz
5cf1a8fcfc feat: refonte vita
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2024-09-16 19:28:07 +02:00
Kazhnuz
ed6e1e6a47 feat: tentative de définition des stats de PNJ
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2024-09-16 16:36:58 +02:00
Kazhnuz
5e8d7a19e1 feat: adaptation des boost d'armes
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2024-09-02 16:29:27 +02:00
Kazhnuz
fcea7f2e4b fix: utilisation des rangs plutôt que des niveaux
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-02 15:51:37 +02:00
Kazhnuz
7deebcf64c feat: ajout d'un simulateur
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-02 14:36:10 +02:00
Kazhnuz
b1b481536e feat: ajout d'un systeme de bestiaire
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-15 10:42:55 +02:00
117 changed files with 2509 additions and 428 deletions

View file

@ -21,7 +21,7 @@ steps:
settings: settings:
hosts: hosts:
from_secret: deploy_host from_secret: deploy_host
target: /var/www/next.erratum.kazhnuz.space target: /var/www/erratum.kazhnuz.space
source: _site/* source: _site/*
user: user:
from_secret: deploy_user from_secret: deploy_user

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

View file

@ -2,7 +2,7 @@
layout: layouts/parent.njk layout: layouts/parent.njk
--- ---
<div id="core"> <div id="core">
<main id="skip" class="visible"> <main id="skip">
<div> <div>
{{ content | safe }} {{ content | safe }}
</div> </div>
@ -18,7 +18,7 @@ layout: layouts/parent.njk
</div> </div>
{%- endif -%} {%- endif -%}
<div class="card" id="sommaire"> <div class="card">
<h2>Sommaire</h2> <h2>Sommaire</h2>
{{ content | toc | safe }} {{ content | toc | safe }}
</div> </div>

View file

@ -2,7 +2,7 @@
layout: layouts/parent.njk layout: layouts/parent.njk
--- ---
<div id="core"> <div id="core">
<main id="skip" class="visible"> <main id="skip">
<div> <div>
{{ content | safe }} {{ content | safe }}
</div> </div>
@ -18,7 +18,7 @@ layout: layouts/parent.njk
</div> </div>
{%- endif -%} {%- endif -%}
<div class="card" id="sommaire"> <div class="card">
<h2>Sommaire</h2> <h2>Sommaire</h2>
{{ content | toc | safe }} {{ content | toc | safe }}
</div> </div>

View file

@ -31,10 +31,12 @@
<nav> <nav>
<h2 class="visually-hidden">Top level navigation menu</h2> <h2 class="visually-hidden">Top level navigation menu</h2>
<ul class="nav"> <ul class="nav">
<li class="nav-item"><a href="/">Accueil</a></li>
<li class="nav-item"><a href="/about/">À propos</a></li>
<li class="nav-item"><a href="/tl-dr/">TL; DR</a></li> <li class="nav-item"><a href="/tl-dr/">TL; DR</a></li>
</ul> </ul>
<ul class="nav"> <ul class="nav">
<li class="nav-item"><a href="/fiches/">Fiches</a></li> <li class="nav-item"><a href="/fiches/">Fiches téléchargeables</a></li>
<li class="nav-item"><a href="https://git.kobold.cafe/univers/erratum">Code Source</a></li> <li class="nav-item"><a href="https://git.kobold.cafe/univers/erratum">Code Source</a></li>
</ul> </ul>
</nav> </nav>
@ -54,9 +56,6 @@
<!-- Current page: {{ page.url | htmlBaseUrl }} --> <!-- Current page: {{ page.url | htmlBaseUrl }} -->
<div class="mobile-buttons"><button id="menu-button">Menu</button><button id="sommaire-button">Sommaire</button></div>
<script src="/js/mobile-sidebar.js"></script>
<script> <script>
const myTable = document.querySelector("#dataTable table"); const myTable = document.querySelector("#dataTable table");

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

@ -1,18 +1,5 @@
# Changelog # Changelog
## [2.6.1] - 2024-10-17
### Ajoutés
- Ajout des combats de batailles
- Ajout d'un robots.txt
### Modifiés
- Modifications des tableaux pour utiliser plus souvent des verticaux
- Modification du site pour le rendre responsive
- Masquage des éléments futurs
## [2.6.0] - 2024-09-11 ## [2.6.0] - 2024-09-11
### Refonte DfOS ### Refonte DfOS

27
content/about.md Normal file
View file

@ -0,0 +1,27 @@
---
layout: layouts/home.njk
---
# À propos
Ce site est un petit site de présentation de mon JDR {{ metadata.title }}. Il a pour but de vous présenter les différents éléments qui le composent, les différentes règles.
Pourquoi cette page ? Et bien, faisant des parties de ma campagne Erratum avec mes amis, je me suis retrouvé comme beaucoup de MJ avec une situation qui peut être parfois casse-pied... Devoir gérer 300 versions du livre de règles différentes parce que le fichier .odt a été passé à plusieurs personnes, modifié sur le tas, etc. Étant particulièrement fainéant, j'ai commencé à me dire que toute possibilité de moins bosser était la plus belle chose qui pouvait m'arriver. Du coup, voici le site du rulebook ! Un petit eleventy, quelques fichiers markdown sur des branches d'un dépot.
Cette page vous donne accès au lore de l'univers et aux différents sets de règles que j'ai fais pour mes différentes campagnes.
## Infos de copyright
Cet univers et ses JDRs associés sont mis à disposition selon les termes de la [licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/). Vous êtes libre d'utiliser cet univers, ainsi que les règles de jeux, comme base pour ce que vous voulez, à condition de repartager dans les mêmes conditions les contenus qui seraient basé sur cet univers. Il est à noter que cette licence ne couvre pas l'inspiration : vous pouvez vous inspirer de certains concepts ou idées sans que ce soit couvert par la licence, dans ce cas vous n'avez pas d'obligation d'utiliser la licence creative commons.
( À noter qu'utiliser le contenu de ce site pour entrainer une AI n'est pas de l'inspiration #NoAI )
## Crédits
- Site généré grâce à [Eleventy](11ty.org)
- Icone [Night-Sky](https://game-icons.net/1x1/lorc/night-sky.html) par [Lorc](https://lorcblog.blogspot.com/) sous [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/)
- Icone [Pine-Tree](https://game-icons.net/1x1/lorc/pine-tree.html) par [Lorc](https://lorcblog.blogspot.com/) sous [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/)
- Icone [Dead wood](https://game-icons.net/1x1/lorc/dead-wood.html) par [Lorc](https://lorcblog.blogspot.com/) sous [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/)
- Favicon venant du set de tiles [Castlevania-esque Tilemap](https://opengameart.org/content/castlevania-esque-tilemap-stone-and-bricks) par [Richy Mackro](https://chayed-creates.itch.io/chayed-creates-pixels) sous [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
- Merci à Marcel Dupoignard et mon groupe de JDR pour de nombreux éléments de cet univers
- Relecture et illustration de la page d'accueil par Nepeta Sibirica

View file

@ -1,23 +1,21 @@
--- ---
layout: layouts/base.njk layout: layouts/base.njk
eleventyNavigation: eleventyNavigation:
key: L'expérience key: L'expérience (old)
parent: Classes et experiences parent: Classes et experiences
order: 10 order: 10
--- ---
# L'expérience # L'expérience
Les augmentation de niveau de signe faisait avoir obtenir d'un coup toutes les compétences d'un personnages, mais coutait de plus en plus cher, et par niveau (et non par groupe de niveau). Suite des nombres premiers suivant le niveau de difficulté. Lorsque double-signe, la liste devient. > Note: Cette page représente l'ancien système de gestion de l'expérience d'Erratum, pour le nouveau système, voyez la page [**Niveaux**](/classes/niveaux)
<div class="table-responsive"> Dans l'ancien système d'Erratum, les augmentation de niveau de signe faisait avoir obtenir d'un coup toutes les compétences d'un personnages, mais coutait de plus en plus cher, et par niveau (et non par groupe de niveau). Suite des nombres premiers suivant le niveau de difficulté. Lorsque double-signe, la liste devient.
| Premier Signe ou autre type de classe (naturel) | Deuxième signe (apothéose) | Troisième signe (apothéose²) | | Premier Signe ou autre type de classe (naturel) | Deuxième signe (apothéose) | Troisième signe (apothéose²) |
|:-----------:|:--:|:--:| |:-----------:|:--:|:--:|
| 1-2-3-5-7-11 | 2-3-5-7-11-13 | 3-5-7-11-13-17 | | 1-2-3-5-7-11 | 2-3-5-7-11-13 | 3-5-7-11-13-17 |
</div>
## Augmentations de stats ## Augmentations de stats
L'augmentation de stats est limitée par la présence ou non de potentiel, de la manière suivante : L'augmentation de stats est limitée par la présence ou non de potentiel, de la manière suivante :

View file

@ -10,10 +10,14 @@ parent: Les magies
# Les arts martiaux # Les arts martiaux
Les arts martiaux sont une magie tirée de la *force martiale*. La force martiale se concentre dans le corps pour transformer les capacités utilisés. Les arts martiaux sont une magie tirée de la force martiale. La force martiale se concentre dans le corps pour transformer les capacités utilisés.
Les arts martiaux existent en de nombreuses écoles, et peut être apprise avec des maitres martialistes. Les arts martiaux existent en de nombreuses écoles, et peut être apprise avec des maitres martialistes.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| La Grande Force Martiale | Peu Commun | FOR |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -14,6 +14,10 @@ La magie créatrice consiste à maîtriser une matière nommée le sidérale, co
C'est une des magies les plus rares et difficile à maitriser. C'est une des magies les plus rares et difficile à maitriser.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| La puissance créatrice | Rare | INT, HAB |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -14,6 +14,10 @@ La magie élémentaire est une magie se basant sur les pouvoirs des grands élé
Les utilisateurs font un pacte avec certains nombres d'éléments qui pourront ensuite être utilisé. Les utilisateurs font un pacte avec certains nombres d'éléments qui pourront ensuite être utilisé.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| Grands élémentaires | Commune | INT, HAB |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -14,6 +14,10 @@ Les enchantements sont une magie plutôt rare, consistant à appliquer des effet
Cette magie se fonde sur les circuits de magie existant partout, formé par la circulation naturelle de l'éclat dans tout ce qui existe. Cette magie se fonde sur les circuits de magie existant partout, formé par la circulation naturelle de l'éclat dans tout ce qui existe.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| Les circuits magiques naturels | Rare | HAB |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -1,6 +1,6 @@
--- ---
layout: layouts/base.njk layout: layouts/base.njk
title: Lherboristerie title: Lherboristerie (old)
tags: Magies Communes tags: Magies Communes
models: models:
- Magies Communes - Magies Communes
@ -8,10 +8,16 @@ models:
parent: Les magies parent: Les magies
--- ---
# Lherboristerie # Lherboristerie (ancienne version)
> **Note** : Cette version de l'herboristerie est dépréciée et sera retirée dans une version future. Cliquez ici pour accéder à [la nouvelle](/classes/magies/herboristerie/).
L'herboristerie est sans doute la magie la moins magique. Elle tire son pouvoir de plantes particulières, les plantes élémentaires. Ces plantes sont alors mélangées pour créer des effets spéciaux dans des potions. L'herboristerie est sans doute la magie la moins magique. Elle tire son pouvoir de plantes particulières, les plantes élémentaires. Ces plantes sont alors mélangées pour créer des effets spéciaux dans des potions.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| Les plantes | Commune | INT, HAB |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -1,6 +1,11 @@
--- ---
layout: layouts/base.njk layout: layouts/base.njk
title: Lherboristerie title: Lherboristerie
tags: Magies Communes
models:
- Magies Communes
- Magies Rares
parent: Les magies
--- ---
# Lherboristerie # Lherboristerie
@ -9,6 +14,10 @@ title: Lherboristerie
L'herboristerie est sans doute la magie la moins magique. Elle tire son pouvoir de plantes particulières, les plantes élémentaires. Ces plantes sont alors mélangées pour créer des effets spéciaux dans des potions. L'herboristerie est sans doute la magie la moins magique. Elle tire son pouvoir de plantes particulières, les plantes élémentaires. Ces plantes sont alors mélangées pour créer des effets spéciaux dans des potions.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| Les plantes | Commune | INT, HAB |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -12,6 +12,10 @@ parent: Les magies
Les invocations sont un type de magie consistant à utiliser son encrage dans le monde physique pour invoquer un démon, une espèce proche des demi-dieux lié au *chaos* possédant un ou plusieurs pouvoirs démoniaques uniques. Les invocations sont un type de magie consistant à utiliser son encrage dans le monde physique pour invoquer un démon, une espèce proche des demi-dieux lié au *chaos* possédant un ou plusieurs pouvoirs démoniaques uniques.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| Démons | Peu commune | VOL+CHA |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -12,6 +12,12 @@ parent: Les magies
La magie naturelle est la magie consistant à utiliser à son avantage les forces de la nature et des animaux. Cette magie est grandement appréciée des gens n'ayant pas forcément de fort pouvoir magique, et peut s'apprendre en autodidacte par un fort contact avec la nature. La magie naturelle est la magie consistant à utiliser à son avantage les forces de la nature et des animaux. Cette magie est grandement appréciée des gens n'ayant pas forcément de fort pouvoir magique, et peut s'apprendre en autodidacte par un fort contact avec la nature.
En Neustrie, les mages de la nature les plus réputés sont les *druides*.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| Mère nature | Peu commun | REL |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -12,6 +12,10 @@ parent: Les magies
La magie spirituelle, ou shamanisme, est la magie consistant à utiliser les pouvoirs des spectres, des êtres entièrement mentaux. Magie proche de la magie élémentaire, mais portant sur la magie métaphysique, et de la magie naturelle, on peut imaginer qu'elle s'est formé par un mélange des deux. La magie spirituelle, ou shamanisme, est la magie consistant à utiliser les pouvoirs des spectres, des êtres entièrement mentaux. Magie proche de la magie élémentaire, mais portant sur la magie métaphysique, et de la magie naturelle, on peut imaginer qu'elle s'est formé par un mélange des deux.
| Sources | Rareté | Stats privilégié |
|:--:|:--:|:--:|
| Les spectres et esprits | Peu commune | INT, HAB |
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -1,5 +1,9 @@
--- ---
layout: layouts/base.njk layout: layouts/base.njk
eleventyNavigation:
key: Les niveaux
parent: Classes et experiences
order: 1
--- ---
# Les niveaux # Les niveaux
@ -10,8 +14,8 @@ Pour symboliser l'évolution d'un personnage, Erratum utilise un système de niv
Chaque augmentation de niveau donne : Chaque augmentation de niveau donne :
- Des augmentations ou modifications de pouvoirs - Des augmentations ou modifications de pouvoirs
- Des augmentations de compétences - Des *points de compétences* utilisable pour améliorer ses compétences
- Des augmentations de statistiques - Des *points d'entrainement* utilisable pour améliorer ses statistiques
De plus, certains groupes de niveaux représentent des *rang* qui affecte quel genre de compétences sont disponibles, quels limites de stats sont possibles, etc. De plus, certains groupes de niveaux représentent des *rang* qui affecte quel genre de compétences sont disponibles, quels limites de stats sont possibles, etc.
@ -25,26 +29,35 @@ Un personnage peut gagner de niveau quand ces explois sont au delà de ce qu'on
Dans les cas trouble, il est possible de lancer un D100, et augmenter de niveau suivant un score défini par le MJ. L'augmentation de niveau est à voir par l'idée que le personnage à "atteint un nouveau palier", plus que "il a gagné +1 expérience" : il faut voir ça comme "après ce que vous avez fait, ouais c'est logique que vous soyez niveau 6". Dans les cas trouble, il est possible de lancer un D100, et augmenter de niveau suivant un score défini par le MJ. L'augmentation de niveau est à voir par l'idée que le personnage à "atteint un nouveau palier", plus que "il a gagné +1 expérience" : il faut voir ça comme "après ce que vous avez fait, ouais c'est logique que vous soyez niveau 6".
## Augmentation des pouvoirs
Votre personnage reçoit pour chaque avancée de niveau *deux points de compétence* à dépenser pour obtenir une compétence, à l'exception des cinq niveaux suivants:
- Le niveau 8 où il obtient à la place son *pouvoir personnel*.
- Le niveau 12 où il obtient à la place une *augmentation de puissance de 5 pouvoirs*.
- Le niveau 15 où il améliore son *pouvoir personnel*.
- Le niveau 19 où il obtient à la place une *augmentation de puissance de 5 nouveaux pouvoirs*.
- Le niveau 20 où il améliore son *pouvoir personnel*.
Les augmentation de pouvoir permette d'améliorer les effets d'un des pouvoirs que possède le personnage.
### Pouvoir personnel
Le pouvoir personnel est une capacité signature que le personnage possède en combat. Cette capacité peut être passive ou active, et sera améliorable deux fois, la deuxième amélioration étant celle du niveau 20.
Ce pouvoir doit être lié de manière RP/logique au personnage, c'est à dire qu'elle doit être en accord avec ce qu'il fait, ses spécialités, ses traits de personnalités, sa façon de faire et/ou ses classes.
## Amélioration de compétence et statistiques ## Amélioration de compétence et statistiques
Chaque personnage obtient à chaque niveau *5 points d'entrainement*, qui peuvent être utiliser pour acquérir et augmenter des compétences et/ou des statistiques de la manière suivante : Chaque personnage obtient à chaque niveau *3 points de compétences* et *3 points d'entrainement*, qui peuvent être utiliser pour acquérir et augmenter des compétences et/ou des statistiques.
- Permet d'ajouter +10% à une compétence - Un point de compétence permet de gagner 10% à une compétence (dans les limites accessible au personnage à son niveau)
- Permet d'ajouter +5% à une statistiques - Un point d'entrainement permet de gagner soit 5% à une statistique, soit 3 PV ou PE, soit augmenter ou diminuer de 1 la pression du personnage
- (Coute 2 point d'exp en supérieur à 100)
- Permet d'ajouter +3 PE/PV à un personnage
- Permet de diminuer ou augmenter d'un la pression
- Permet de gagner un pouvoir d'une classe
- Permet d'améliorer ou de personnaliser un pouvoir d'une classe (1/compétence)
En tout, un personnage utilisera 100 points d'expérience au court de son aventure.
## Les rangs ## Les rangs
Les rangs sont des groupes de niveaux débloquant des compétences et des pouvoirs. Il y a en tout six rangs. Les rangs sont des groupes de niveaux débloquant des compétences et des pouvoirs. Il y a en tout six rangs.
<div class="table-responsive">
| Niveaux | Rang | Niveau classe | Débloque | Max bonus PV/PE | Max compétence | | Niveaux | Rang | Niveau classe | Débloque | Max bonus PV/PE | Max compétence |
|:-------:|:---:|:-------------:|:--------:|:---------------:|:--------------:| |:-------:|:---:|:-------------:|:--------:|:---------------:|:--------------:|
| 1 à 2 | D | Novice (1 et 2) | | +100% | 30% | | 1 à 2 | D | Novice (1 et 2) | | +100% | 30% |
@ -54,8 +67,6 @@ Les rangs sont des groupes de niveaux débloquant des compétences et des pouvoi
| 16 à 18 | S | Ultime (6) | Potentiel+ | +500% | 50% | | 16 à 18 | S | Ultime (6) | Potentiel+ | +500% | 50% |
| 19, 20 | X | Ultime (6) | | +600% | 70% | | 19, 20 | X | Ultime (6) | | +600% | 70% |
</div>
Les deux premiers rang, *D* et *C* représentent la plupart des "civils", ou personnes n'ayant pas obtenu des compétences incroyables dans leur domaine, ni vécus d'aventures. Les deux premiers rang, *D* et *C* représentent la plupart des "civils", ou personnes n'ayant pas obtenu des compétences incroyables dans leur domaine, ni vécus d'aventures.
## Classes de départ ## Classes de départ

View file

@ -17,14 +17,10 @@ Les balances tirent leur pouvoir de l'équilibre : que celui-ci soit entre les s
On rapproche pour ce fait de l'arcane de la justice, avec l'ide de manipuler les gains et les blessures. On rapproche pour ce fait de l'arcane de la justice, avec l'ide de manipuler les gains et les blessures.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :libra: | Chien (asie), Maât (égypte) | Guérison et malice (Healer Trickster) | Ordre | Peu commun (05.5%) | SAG et INT | Vert | | :libra: | Chien (asie), Maât (égypte) | Guérison et malice (Healer Trickster) | Ordre | Peu commun (05.5%) | SAG et INT | Vert |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -17,14 +17,10 @@ Les béliers tirent leur pouvoir des autres, et des responsabilités qu'iels ont
Chef ou protecteur de l'ombre, ils sont des gardiens du troupeaux, ceux qui peuvent faire en sorte que c'est tous qui réussissent, et pas juste certains. Chef ou protecteur de l'ombre, ils sont des gardiens du troupeaux, ceux qui peuvent faire en sorte que c'est tous qui réussissent, et pas juste certains.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :aries: | ??? (asie), ??? (égypte) | Protection et Guérison (Tank Soigneur) | Ordre | Peu commun (9.5%) | CON et REL | Or | | :aries: | ??? (asie), ??? (égypte) | Protection et Guérison (Tank Soigneur) | Ordre | Peu commun (9.5%) | CON et REL | Or |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -17,14 +17,10 @@ Le signe cancer, signe du phénotype, est un signe rare offrant le pouvoir de co
Cela dit, cela rend aussi leur soins dangereux pour ceux qui le subissent. Ils peuvent créer des soins particulièrement performant au prix d'effet secondaire redoutable. Il s'agit d'un signe rare et puissant. Cela dit, cela rend aussi leur soins dangereux pour ceux qui le subissent. Ils peuvent créer des soins particulièrement performant au prix d'effet secondaire redoutable. Il s'agit d'un signe rare et puissant.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :cancer: | Rat (asie) | Guérison et Force (Soigneur DPS) | Chaos | Rare (01.2%) | INT et HAB | Gris | | :cancer: | Rat (asie) | Guérison et Force (Soigneur DPS) | Chaos | Rare (01.2%) | INT et HAB | Gris |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -17,14 +17,10 @@ Les capricornes tirent leur pouvoir des émotions et de leur puissance. En effet
Leur pouvoir les permet de se sortir de bien des situations, mais aussi d'être les plus à même à attaquer sur l'esprit. Politiciens, espions... Mais ils peuvent aussi être des aides quand ils le veulent. Telle est toute l'ambivalence de ceux qui contrôlent les émotions. Leur pouvoir les permet de se sortir de bien des situations, mais aussi d'être les plus à même à attaquer sur l'esprit. Politiciens, espions... Mais ils peuvent aussi être des aides quand ils le veulent. Telle est toute l'ambivalence de ceux qui contrôlent les émotions.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :capricorn: | ??? (asie), ??? (égypte) | Malice et Force (Trickster DPS) | Chaos | Peu commun (10.0%) | REL et CHA | Orange | | :capricorn: | ??? (asie), ??? (égypte) | Malice et Force (Trickster DPS) | Chaos | Peu commun (10.0%) | REL et CHA | Orange |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |
@ -56,7 +52,7 @@ Leur pouvoir les permet de se sortir de bien des situations, mais aussi d'être
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |
|:---:|:--------:|:-----------------------------------------| |:---:|:--------:|:-----------------------------------------|
| 5 | Nudisme | Créer une émotion provoquant leffet « Nudisme » à la cible, pour un seul tour. La cible peut ensuite prendre un tour pour les rééquiper. L'action se résiste sur un jet de SAG ou VOL dégressif, à -10/tour. | | 5 | Nudisme | Donne leffet « Nudisme » à la cible. |
| 5 | Nan mais là faut se calmer | Sur un jet de CHA ou REL, peut tenter de stopper laction dun autre PJ, même si celle-ci est entamée. Si celui-ci na pas agit de son chef, il doit faire un jet de CHA opposé pour resister ou non. Sil a agit de son chef, peut choisir découter la petite voix dans sa tête. (II : Ladversaire à un malus de 30 % pour résister) | | 5 | Nan mais là faut se calmer | Sur un jet de CHA ou REL, peut tenter de stopper laction dun autre PJ, même si celle-ci est entamée. Si celui-ci na pas agit de son chef, il doit faire un jet de CHA opposé pour resister ou non. Sil a agit de son chef, peut choisir découter la petite voix dans sa tête. (II : Ladversaire à un malus de 30 % pour résister) |
| 5 | Émotion+ | Passe les afflictions mentales provoquées au niveau supérieur | | 5 | Émotion+ | Passe les afflictions mentales provoquées au niveau supérieur |

View file

@ -17,14 +17,10 @@ Les gémeaux sont à la fois un seul être et plusieurs, un corps et un esprit d
Le dédoublement provoque cependant toujours un effet : l'esprit étant étendu entre deux corps (que ce soit sous la forme d'un ou deux esprits), il a le pouvoir de s'étendre encore plus sur tout ce qui entoure, et d'affecter tout ce qui entoure. Le dédoublement provoque cependant toujours un effet : l'esprit étant étendu entre deux corps (que ce soit sous la forme d'un ou deux esprits), il a le pouvoir de s'étendre encore plus sur tout ce qui entoure, et d'affecter tout ce qui entoure.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :gemini: | ??? (asie), ??? (égypte) | Malice et Guérison (Trickster Healer) | Chaos | Commun (15.0%) | VOL et INT | Indigo | | :gemini: | ??? (asie), ??? (égypte) | Malice et Guérison (Trickster Healer) | Chaos | Commun (15.0%) | VOL et INT | Indigo |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -21,8 +21,6 @@ Le serpentaire n'a pas de hérault.
Les 12 **héraults de signes** permettent d'obtenir les pouvoirs de herault de chaque signe. Les 12 **héraults de signes** permettent d'obtenir les pouvoirs de herault de chaque signe.
<div class="table-responsive">
| Signe | Hérault | Description | Période | Localisation | | Signe | Hérault | Description | Période | Localisation |
|:-----:|:-------:|:-----------:|:-------:|:------------:| |:-----:|:-------:|:-----------:|:-------:|:------------:|
| Cancer | **Ibn Sina** (Avicenne) | Fondateur de la médecine moderne | 10~11e siècle | Hamadan | | Cancer | **Ibn Sina** (Avicenne) | Fondateur de la médecine moderne | 10~11e siècle | Hamadan |
@ -38,14 +36,10 @@ Les 12 **héraults de signes** permettent d'obtenir les pouvoirs de herault de c
| Capricorne | **Médée** | Héroine et sorcière grecque, ayant aidé et été trahie par les Argonaute | 17e siècle avant JC | Méditérannée | | Capricorne | **Médée** | Héroine et sorcière grecque, ayant aidé et été trahie par les Argonaute | 17e siècle avant JC | Méditérannée |
| Poisson | **?????** | Hérault inconnu⋅e. On raconte que son temple est entièrement une illusion. | ??? | Partout | | Poisson | **?????** | Hérault inconnu⋅e. On raconte que son temple est entièrement une illusion. | ??? | Partout |
</div>
## Hérault d'Arcane ## Hérault d'Arcane
Les **hérault d'Arcane** ou **Grand-Hérault** sont quatre être ayant maitrisé tout les aspect d'une arcane, et pouvant donc offrir des nouveaux pouvoir à un⋅e manipulateur⋅ice de ladite arcane. Ces quatre êtres sont à la limite entre divinité et humanité. Ils sont aux nombres de 4. Les **hérault d'Arcane** ou **Grand-Hérault** sont quatre être ayant maitrisé tout les aspect d'une arcane, et pouvant donc offrir des nouveaux pouvoir à un⋅e manipulateur⋅ice de ladite arcane. Ces quatre êtres sont à la limite entre divinité et humanité. Ils sont aux nombres de 4.
<div class="table-responsive">
| Arcane | Hérault | Description | Période | Localisation | | Arcane | Hérault | Description | Période | Localisation |
|:-----:|:-------:|:-----------:|:-------:|:------------:| |:-----:|:-------:|:-----------:|:-------:|:------------:|
| Guérison | **Nokomis** (Grand-Mère Feuillage) | Danaïte mythique devenu une avec la nature | Ancestrale | Amérique du Nord | | Guérison | **Nokomis** (Grand-Mère Feuillage) | Danaïte mythique devenu une avec la nature | Ancestrale | Amérique du Nord |
@ -53,8 +47,6 @@ Les **hérault d'Arcane** ou **Grand-Hérault** sont quatre être ayant maitris
| Protection | **Hervor** | Grande héroïne Skjaldmö ayant pu jusqu'à rivaliser avec les valkyrie | 4e siècle | Scandinavie | | Protection | **Hervor** | Grande héroïne Skjaldmö ayant pu jusqu'à rivaliser avec les valkyrie | 4e siècle | Scandinavie |
| Malice | **Maui** | Grand trickster et protecteur des hommes en polynésies et dans tout le pacifique | -3000 | Polynésie | | Malice | **Maui** | Grand trickster et protecteur des hommes en polynésies et dans tout le pacifique | -3000 | Polynésie |
</div>
### Pouvoirs des Héraults ### Pouvoirs des Héraults
| Arcane | Pouvoirs | Effet | | Arcane | Pouvoirs | Effet |
@ -70,8 +62,6 @@ Les **hérault d'Arcane** ou **Grand-Hérault** sont quatre être ayant maitris
Les 12 heraults permettent d'obtenir les pouvoirs de herault de chaque signe. Les 12 heraults permettent d'obtenir les pouvoirs de herault de chaque signe.
<div class="table-responsive">
| Signe | Hérault | Description | Période | Localisation | | Signe | Hérault | Description | Période | Localisation |
|:-----:|:-------:|:-----------:|:-------:|:------------:| |:-----:|:-------:|:-----------:|:-------:|:------------:|
| Cancer | **Ibn Sina** (Avicenne) | Fondateur de la médecine moderne | 10~11e siècle | Hamadan | | Cancer | **Ibn Sina** (Avicenne) | Fondateur de la médecine moderne | 10~11e siècle | Hamadan |
@ -86,5 +76,3 @@ Les 12 heraults permettent d'obtenir les pouvoirs de herault de chaque signe.
| Gémeaux | **Xolotl** | Frère jumeaux du dieu Quetzacoatl | 10e siècle | Mexique | | Gémeaux | **Xolotl** | Frère jumeaux du dieu Quetzacoatl | 10e siècle | Mexique |
| Capricorne | **Socrate** | Philosophe, et un peu un troll aussi | 5e siècle avant JC | Grèce | | Capricorne | **Socrate** | Philosophe, et un peu un troll aussi | 5e siècle avant JC | Grèce |
| Poisson | **?????** | Hérault inconnu⋅e. On raconte que son temple est entièrement une illusion. | ??? | Partout | | Poisson | **?????** | Hérault inconnu⋅e. On raconte que son temple est entièrement une illusion. | ??? | Partout |
</div>

View file

@ -19,14 +19,10 @@ Ils sont plus fort quand ils sont en danger, et leur pouvoirs permettent de se b
Leur herault est Gilgamesh, le roi-héros, aux exploits légendaires qui ont transcendé l'histoire et les légendes, vers -3000. Leur herault est Gilgamesh, le roi-héros, aux exploits légendaires qui ont transcendé l'histoire et les légendes, vers -3000.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :leo: | Tigre (asie), ??? (égypte) | Force et Protection (DPS Tank) | Ordre | Rare (02.2%) | CHA, FOR et VOL | Rouge | | :leo: | Tigre (asie), ??? (égypte) | Force et Protection (DPS Tank) | Ordre | Rare (02.2%) | CHA, FOR et VOL | Rouge |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -17,14 +17,10 @@ Les poissons tirent leur pouvoir des apparences, des mystères et du spectacle.
Leur pouvoir est celui des illusions. Ils se protègent en n'étant pas présent là où vous attaquez. Ils vous font voir des choses fausses... Mais est-ce forcément offensif ? Ne peuvent-ils pas aussi être les aêdes dont les récit peuples votre imaginaire ? Leur pouvoir est celui des illusions. Ils se protègent en n'étant pas présent là où vous attaquez. Ils vous font voir des choses fausses... Mais est-ce forcément offensif ? Ne peuvent-ils pas aussi être les aêdes dont les récit peuples votre imaginaire ?
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :pisces: | Singe (asie), Seth (égypte) | Malice et Protection (Trickster Tank) | Chaos | Rare (1.9%) | DIS | Pourpre | | :pisces: | Singe (asie), Seth (égypte) | Malice et Protection (Trickster Tank) | Chaos | Rare (1.9%) | DIS | Pourpre |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -17,14 +17,10 @@ Les sagittaire tirent leur pouvoir du mouvement et de la vitesse. Capable d'effe
Rapide, précis, cette maitrise les rendent généralement cependant plutôt fragile et ils privilégie un grand nombre d'action de faible puissance comparé à une seule action extrèmement forte. Rapide, précis, cette maitrise les rendent généralement cependant plutôt fragile et ils privilégie un grand nombre d'action de faible puissance comparé à une seule action extrèmement forte.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :sagittarius: | ??? (asie), ??? (égypte) | Force et Malice (DPS Trickster) | Ordre | Commun (12.0%) | HAB et PER | Turquoise | | :sagittarius: | ??? (asie), ??? (égypte) | Force et Malice (DPS Trickster) | Ordre | Commun (12.0%) | HAB et PER | Turquoise |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -17,14 +17,10 @@ Les scorpions tirent leurs pouvoirs des poisons. Ils deviennent capables d'en s
Ils sont aussi bien médecins comme attaquants ; ne dit-on pas que les médecines ne sont que des poisons bien utilisés ? Ils sont aussi bien médecins comme attaquants ; ne dit-on pas que les médecines ne sont que des poisons bien utilisés ?
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :scorpius: | Serpent (asie), ??? (égypte) | Force et Guérison (DPS Soigneur) | Chaos | Commun (15.0%) | HAB | Violet sombre | | :scorpius: | Serpent (asie), ??? (égypte) | Force et Guérison (DPS Soigneur) | Chaos | Commun (15.0%) | HAB | Violet sombre |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

View file

@ -17,14 +17,10 @@ Le serpentaire est le 13 signes, le signe inconnu, celui qui ne devrait pas exis
Le serpentaire n'est en fait pas un signe. Il est un méta-signe. Il permet de contrôler les flux même de la magie. Le serpentaire n'est en fait pas un signe. Il est un méta-signe. Il permet de contrôler les flux même de la magie.
<div class="table-responsive">
| Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur | | Symb | Autre nom | Arcanes | Alignement | Rareté | Stats privilégié | Couleur |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| :ophiuchus: | ??? (asie), ??? (égypte) | Hors du système | Éclat | Exceptionnel | SAG et VOL | Toutes/blanc. | | :ophiuchus: | ??? (asie), ??? (égypte) | Hors du système | Éclat | Exceptionnel | SAG et VOL | Toutes/blanc. |
</div>
## Pouvoir de base ## Pouvoir de base
| Niv | Pouvoirs | Effet | | Niv | Pouvoirs | Effet |

Some files were not shown because too many files have changed in this diff Show more