var COIE_Loaded = false;
var script_version = 0.2;
var COImportExport = COImportExport || function() {
'use strict';
function sendPlayer(origin, msg) {
var dest = origin;
if (origin.who) {
if (playerIsGM(origin.playerid)) dest = 'GM';
else dest = origin.who;
}
sendChat('COIE', '/w "' + dest + '" ' + msg);
}
//Fonction inutile maintenant que le turn action n'est plus nécessaire pour
//afficher les actions du personnage à son tour.
function turn_action(msg) {
if (msg.selected !== undefined) {
var all_characters = [];
_.each(msg.selected, function(selection) {
var token = getObj("graphic", selection._id);
if (token !== undefined) {
var character = getObj('character', token.get('represents'));
if (character !== undefined) {
all_characters.push(character);
}
}
});
var cpt = 0;
all_characters.forEach(function(character) {
var charId = character.get('_id');
var abilities = findObjs({
_type: 'ability',
_characterid: charId,
});
var turn_action = abilities.filter(function(obj) {
var attrName = obj.get('name');
return (obj.get('name') == '#TurnAction#');
});
if (turn_action.length === 0) {
var action = '';
_.each(abilities, function(ability, i) {
action += '%' + ability.get('name') + '\n';
ability.set('istokenaction', false);
});
var new_ability = createObj("ability", {
_characterid: charId,
name: '#TurnAction#',
description: '',
action: action,
istokenaction: false
});
}
});
}
}
function export_character(msg) {
var json_export = [];
// Toutes les Macros
var macros = findObjs({
_type: 'macro'
});
if (msg.selected !== undefined) {
var all_characters = [];
_.each(msg.selected, function(selection) {
var token = getObj("graphic", selection._id);
if (token !== undefined) {
var character = getObj('character', token.get('represents'));
if (character !== undefined) {
all_characters.push(character);
}
}
});
var cpt = 0;
all_characters.forEach(function(character) {
var charId = character.get('_id');
var character_name = character.get('name');
var export_character = {};
export_character.character = {
name: character_name,
avatar: character.get('avatar'),
gmnotes: '',
bio: '',
};
character.get("gmnotes", function(gmnotes) { // asynchronous
if (gmnotes.length > 0 && gmnotes != 'null')
export_character.character.gmnotes = encodeURIComponent(gmnotes);
character.get("bio", function(bio) { // asynchronous
if (bio.length > 0 && bio != 'null')
export_character.character.bio = encodeURIComponent(bio);
character.get('_defaulttoken', function(defaultToken) {
var attributes = findObjs({
_type: 'attribute',
_characterid: charId,
});
if (defaultToken !== '' && defaultToken !== null) {
var tokenFields = JSON.parse(defaultToken);
if (tokenFields) {
delete tokenFields.represents;
delete tokenFields.pageid;
export_character.defaultToken = {
fields: tokenFields
};
var attrLinked;
if (tokenFields.bar1_link) {
attrLinked = attributes.find(function(a) {
return a.id == tokenFields.bar1_link;
});
if (attrLinked) {
export_character.defaultToken.bar1_link_name = attrLinked.get('name');
delete export_character.defaultToken.fields.bar1_link;
}
}
if (tokenFields.bar2_link) {
attrLinked = attributes.find(function(a) {
return a.id == tokenFields.bar2_link;
});
if (attrLinked) {
export_character.defaultToken.bar2_link_name = attrLinked.get('name');
delete export_character.defaultToken.fields.bar2_link;
}
}
}
}
export_character.attributes = [];
var isTtypePersonnagePresent = false;
_.each(attributes, function(attribute, i) {
var attName = attribute.get('name');
isTtypePersonnagePresent = (attName === 'type_personnage');
export_character.attributes.push({
name: attribute.get('name'),
current: attribute.get('current'),
max: attribute.get('max')
});
});
if (!isTtypePersonnagePresent) {
export_character.attributes.push({
name: 'type_personnage',
current: 'PJ',
max: ''
});
}
var abilities = findObjs({
_type: 'ability',
_characterid: charId,
});
export_character.abilities = [];
_.each(abilities, function(ability, i) {
var action = ability.get('action').trim();
if (action.indexOf('#') !== -1) {
// Cette commande contient au moins une macro donc on va le remplacer par sa commande (action)
var command_words = action.split("\n");
//chaque ligne
_.each(command_words, function(line, j) {
var line_words = line.split(' ');
//chaque mot
_.each(line_words, function(word, k) {
// si le mot commence par #
if (word.startsWith('#')) {
// on recherche une macro qui s'appelle pareil (sans le #)
var this_macro = macros.filter(function(obj) {
return (obj.get('name').trim() == word.substring(1));
});
if (this_macro.length == 1) {
// macro trouvé
// on replace dans la commande initiale
action = action.replace(word, this_macro[0].get('action'));
}
}
});
});
}
export_character.abilities.push({
name: ability.get('name'),
description: ability.get('description'),
action: action,
istokenaction: ability.get('istokenaction')
});
});
json_export.push(export_character);
sendChat('COIE', '/w gm Export ' + character_name + ' effectué.');
cpt++;
if (cpt == all_characters.length) {
// Génère une erreur :
// "ERROR: You cannot set the imgsrc or avatar of an object unless you use an image that is in your Roll20 Library. See the API documentation for more info."
// => c'est "normal" : https://app.roll20.net/forum/post/2405159/api-create-handout-error/?pageforid=2405587
var this_handout = createObj("handout", {
name: 'COExport_' + msg.date
});
this_handout.set('notes', JSON.stringify(json_export));
sendChat('COIE', '/w gm Export terminé.');
}
});
});
});
});
}
}
function parse_charac(MOD, line) {
var characteristic = 0;
line = line.split(MOD + ' ');
if (line[1] !== undefined) {
var value = line[1].trim();
if (value.indexOf(' ')) value = value.split(' ')[0];
if (value.indexOf('+') !== -1) value = value.split('+')[1];
characteristic = value.trim();
}
return parseInt(characteristic);
}
function get_valeur(Mod, line) {
return parseInt(10 + 2 * Mod);
}
function importCharacter() {
var import_handouts = findObjs({
_type: 'handout',
name: 'COImport',
});
if (import_handouts.length === 0) return;
// Tous les personnages
var existing_characters = findObjs({
_type: 'character'
});
//On cherche une page valide pour y créer les tokens si besoin
var pageId;
var pages = findObjs({
_type: 'page'
});
if (pages.length > 0) pageId = pages[0].id;
var Added_Characters = [];
import_handouts.forEach(function(import_handout, i) {
import_handout.get('notes', function(notes) { // asynchronous
try {
var all_characters = JSON.parse(notes.replace(/(
|
|<\/p>)/g, '').trim());
_.each(all_characters, function(character_data) {
var character = character_data.character;
// On recherche si un personnage existe déja avec le même nom
// En cas, on ne l'ajoute pas
var character_exists = existing_characters.filter(function(obj) {
return (obj.get('name').trim() == character.name.trim());
});
if (character_exists.length > 0) {
// Un personnage avec le même nom existe déja.
sendChat('COIE', '/w gm ' + character.name + ' existe déjà. Import annulé.');
} else {
// Aucun personnage avec le même nom n'existe => On peut l'ajouter
var new_character = createObj("character", {
name: character.name,
avatar: character.avatar
});
if (character.notes) {
//dans ce cas, on avait l'ancienne version du script, sans encodage
new_character.set('gmnotes', character.gmnotes.replace(/\n/g, '
'));
new_character.set('bio', character.bio.replace(/\n/g, '
'));
} else {
new_character.set('gmnotes', decodeURIComponent(character.gmnotes));
new_character.set('bio', decodeURIComponent(character.bio));
}
var charId = new_character.get('id');
//Gestion du token par défaut
var token;
if (pageId && character_data.defaultToken) {
var tokenFields = character_data.defaultToken.fields;
tokenFields.pageid = pageId;
tokenFields.represents = charId;
token = createObj('graphic', tokenFields);
}
var isTtypePersonnagePresent = false;
var attributes = character_data.attributes;
_.each(attributes, function(attribute, i) {
var attName = attribute.name;
isTtypePersonnagePresent = (attName === 'type_personnage');
var new_attribute = createObj("attribute", {
_characterid: charId,
name: attribute.name,
current: attribute.current,
max: attribute.max
});
if (token) {
if (attName == character_data.defaultToken.bar1_link_name) {
token.set('bar1_link', new_attribute.id);
} else if (attName == character_data.defaultToken.bar2_link_name) {
token.set('bar2_link', new_attribute.id);
}
}
});
if (token) {
setDefaultTokenForCharacter(new_character, token);
token.remove();
}
if (!isTtypePersonnagePresent) {
createObj("attribute", {
_characterid: charId,
name: 'type_personnage',
current: 'PJ',
max: ''
});
}
var abilities = character_data.abilities;
_.each(abilities, function(ability, i) {
var new_ability = createObj("ability", {
_characterid: charId,
name: ability.name,
description: ability.description,
action: ability.action,
istokenaction: ability.istokenaction
});
});
Added_Characters.push(character.name);
}
});
} catch (e) {
if (notes.indexOf('FOR ') !== -1 && notes.indexOf('DEX ') !== -1 && notes.indexOf('CON ') !== -1 && notes.indexOf('INT ') !== -1 && notes.indexOf('SAG') !== -1 && notes.indexOf('CHA ') !== -1 && notes.indexOf('DEF ') !== -1 && notes.indexOf('PV ') !== -1 && notes.indexOf('Init ') !== -1) {
notes = notes.trim().split('
');
var new_character, character = {},
charId, attributes = [],
FOR_MOD = 0,
DEX = 0,
DEX_MOD = 2,
INIT = 0,
cpt = 0,
attack_contact = 0,
attack_distance = 0,
tmp, NIVEAU;
_.each(notes, function(line, i) {
if (i === 0) {
character.name = line.trim();
if (character.name.indexOf('(') !== -1) character.name = character.name.split('(')[0];
new_character = createObj("character", {
name: character.name,
});
charId = new_character.get('id');
} else {
if (line.indexOf('NC ') !== -1) {
NIVEAU = parseInt(line.split('NC ')[1].replace(/[^0-9\.]/g, ''), 10);
if (!NIVEAU || NIVEAU < 1) NIVEAU = 1;
attributes.push({
name: 'NIVEAU',
current: NIVEAU,
max: ''
});
}
if (line.indexOf('FOR ') !== -1) {
FOR_MOD = parse_charac('FOR', line);
attributes.push({
name: 'FORCE',
current: get_valeur(FOR_MOD),
max: ''
});
}
if (line.indexOf('DEX ') !== -1) {
DEX_MOD = parse_charac('DEX', line);
DEX = get_valeur(DEX_MOD);
}
if (line.indexOf('CON ') !== -1) {
attributes.push({
name: 'CONSTITUTION',
current: get_valeur(parse_charac('CON', line)),
max: ''
});
}
if (line.indexOf('INT ') !== -1) {
attributes.push({
name: 'INTELLIGENCE',
current: get_valeur(parse_charac('INT', line)),
max: ''
});
}
if (line.indexOf('SAG ') !== -1) {
attributes.push({
name: 'SAGESSE',
current: get_valeur(parse_charac('SAG', line)),
max: ''
});
}
if (line.indexOf('CHA ') !== -1) {
attributes.push({
name: 'CHARISME',
current: get_valeur(parse_charac('CHA', line)),
max: ''
});
}
if (line.indexOf('DEF ') !== -1) {
attributes.push({
name: 'DEFDIV',
current: parse_charac('DEF', line) - 10 - DEX_MOD,
max: ''
});
}
if (line.indexOf('PV ') !== -1) {
attributes.push({
name: 'PV',
current: parse_charac('PV', line),
max: parse_charac('PV', line)
});
}
if (line.indexOf('(RD ') !== -1) {
attributes.push({
name: 'RDS',
current: parse_charac('(RD', line),
max: ''
});
}
if (line.indexOf('Init ') !== -1) {
INIT = parse_charac('Init', line);
if (Math.floor((DEX - 10) / 2) == Math.floor((INIT - 10) / 2)) {
attributes.push({
name: 'DEXTERITE',
current: INIT,
max: ''
});
} else {
attributes.push({
name: 'DEXTERITE',
current: DEX,
max: ''
});
attributes.push({
name: 'INIT_DIV',
current: INIT - DEX,
max: ''
});
}
}
if (line.indexOf(' DM ') !== -1) {
cpt++;
attack_contact = NIVEAU + FOR_MOD;
attack_distance = NIVEAU + DEX_MOD;
var armenom = '',
armeatk = '@{ATKCAC}',
armeatkdiv = '',
armedmcar = '@{FOR}',
armedmnbde = 1,
armedmde = 4,
armedmdiv = '',
armeportee = 0;
// ici, virer le +
armenom = line.split(' DM ')[0].trim();
tmp = armenom.split(' ');
tmp = tmp[tmp.length - 1];
if (tmp.indexOf('+') !== -1) {
tmp = tmp.split('+');
armeatkdiv = parseInt(tmp[1].replace(/[^0-9\.]/g, ''), 10);
} else if (tmp.indexOf('-') !== -1) {
tmp = tmp.split('-');
armeatkdiv = -parseInt(tmp[1].replace(/[^0-9\.]/g, ''), 10);
}
armenom = armenom.split('+')[0].trim();
if (armenom.indexOf('m)') !== -1) {
tmp = armenom.split('m)');
armenom = armenom.split('(')[0];
tmp = tmp[0].trim().split(' ');
tmp = tmp[tmp.length - 1].split('(');
armeportee = parseInt(tmp[1].trim().replace(/[^0-9\.]/g, ''), 10);
}
armenom = cpt + ' ' + armenom.trim();
if (armeportee > 0) {
armeatk = '@{ATKTIR}';
armedmcar = '0';
}
var dommage = line.split(' DM ')[1].trim();
if (dommage.indexOf('d') !== -1) {
armedmnbde = parseInt(dommage.split('d')[0].trim().replace(/[^0-9\.]/g, ''), 10);
armedmde = dommage.split('d')[1].trim();
if (armedmde.indexOf('+') !== -1) {
tmp = armedmde.split('+');
armedmde = tmp[0].trim();
armedmdiv = tmp[1].trim();
} else if (armedmde.indexOf('-') !== -1) {
tmp = armedmde.split('-');
armedmde = tmp[0].trim();
armedmdiv = -tmp[1].trim();
}
}
armeatkdiv = parseInt(armeatkdiv + ''.replace(/[^0-9\.]/g, ''), 10);
armedmdiv = parseInt(armedmdiv + ''.replace(/[^0-9\.]/g, ''), 10);
if (armeportee === 0) {
armeatkdiv = armeatkdiv - attack_contact;
armedmdiv = armedmdiv - FOR_MOD;
} else {
armeatkdiv = armeatkdiv - attack_distance;
}
if (!armeatkdiv) armeatkdiv = '';
if (!armedmdiv) armedmdiv = '';
var bonus_degat = line.split(' DM ')[0].split(' ');
bonus_degat = bonus_degat[bonus_degat.length - 1];
if (bonus_degat.indexOf('+') !== -1) bonus_degat = bonus_degat.replace('+', '');
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armenom',
current: armenom,
max: ''
});
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armeatk',
current: armeatk,
max: ''
});
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armeatkdiv',
current: armeatkdiv,
max: ''
});
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armedmcar',
current: armedmcar,
max: ''
});
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armedmnbde',
current: armedmnbde,
max: ''
});
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armedmde',
current: armedmde,
max: ''
});
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armedmdiv',
current: armedmdiv,
max: ''
});
attributes.push({
name: 'repeating_armes_' + i + '_' + 'armeportee',
current: armeportee,
max: ''
});
}
}
});
_.each(attributes, function(attribute, i) {
var new_attribute = createObj("attribute", {
_characterid: charId,
name: attribute.name,
current: attribute.current,
max: attribute.max
});
});
Added_Characters.push(character.name);
} else sendChat('COIE', '/w gm Import impossible. Le contenu du handout COImport semble incorrect...');
}
});
});
if (Added_Characters.length > 0) {
sendChat('COIE', '/w gm Import de ' + Added_Characters.join(', ') + ' effectué.');
}
}
function checkCommand(msg) {
msg.content = msg.content.replace(/\s+/g, ' '); //remove duplicate whites
var command = msg.content.split(" ", 1);
switch (command[0]) {
case "!co-export":
export_character(msg);
return;
case "!co-import":
importCharacter();
return;
case "!co-turn_action":
turn_action(msg);
return;
default:
return;
}
}
return {
checkCommand: checkCommand,
importCharacter: importCharacter,
};
}();
on("ready", function() {
COIE_Loaded = true;
log("CO Import/Export version " + script_version + " loaded.");
});
on("chat:message", function(msg) {
"use strict";
if (!COIE_Loaded || msg.type != "api") return;
msg.date = (new Date()).toISOString().split('.')[0].replace('T', '_');
COImportExport.checkCommand(msg);
});
on("change:handout", function(obj) {
if (obj.get('name') == "COImport") COImportExport.importCharacter();
});